ieee80211_hwmp.c revision 234884
1/*- 2 * Copyright (c) 2009 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Rui Paulo under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29#include <sys/cdefs.h> 30#ifdef __FreeBSD__ 31__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_hwmp.c 234884 2012-05-01 16:06:20Z monthadar $"); 32#endif 33 34/* 35 * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP. 36 * 37 * Based on March 2009, D3.0 802.11s draft spec. 38 */ 39#include "opt_inet.h" 40#include "opt_wlan.h" 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/mbuf.h> 45#include <sys/malloc.h> 46#include <sys/kernel.h> 47 48#include <sys/socket.h> 49#include <sys/sockio.h> 50#include <sys/endian.h> 51#include <sys/errno.h> 52#include <sys/proc.h> 53#include <sys/sysctl.h> 54 55#include <net/if.h> 56#include <net/if_media.h> 57#include <net/if_llc.h> 58#include <net/ethernet.h> 59 60#include <net/bpf.h> 61 62#include <net80211/ieee80211_var.h> 63#include <net80211/ieee80211_action.h> 64#include <net80211/ieee80211_input.h> 65#include <net80211/ieee80211_mesh.h> 66 67static void hwmp_vattach(struct ieee80211vap *); 68static void hwmp_vdetach(struct ieee80211vap *); 69static int hwmp_newstate(struct ieee80211vap *, 70 enum ieee80211_state, int); 71static int hwmp_send_action(struct ieee80211_node *, 72 const uint8_t [IEEE80211_ADDR_LEN], 73 const uint8_t [IEEE80211_ADDR_LEN], 74 uint8_t *, size_t); 75static uint8_t * hwmp_add_meshpreq(uint8_t *, 76 const struct ieee80211_meshpreq_ie *); 77static uint8_t * hwmp_add_meshprep(uint8_t *, 78 const struct ieee80211_meshprep_ie *); 79static uint8_t * hwmp_add_meshperr(uint8_t *, 80 const struct ieee80211_meshperr_ie *); 81static uint8_t * hwmp_add_meshrann(uint8_t *, 82 const struct ieee80211_meshrann_ie *); 83static void hwmp_rootmode_setup(struct ieee80211vap *); 84static void hwmp_rootmode_cb(void *); 85static void hwmp_rootmode_rann_cb(void *); 86static void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *, 87 const struct ieee80211_frame *, 88 const struct ieee80211_meshpreq_ie *); 89static int hwmp_send_preq(struct ieee80211_node *, 90 const uint8_t [IEEE80211_ADDR_LEN], 91 const uint8_t [IEEE80211_ADDR_LEN], 92 struct ieee80211_meshpreq_ie *, 93 struct timeval *, struct timeval *); 94static void hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *, 95 const struct ieee80211_frame *, 96 const struct ieee80211_meshprep_ie *); 97static int hwmp_send_prep(struct ieee80211_node *, 98 const uint8_t [IEEE80211_ADDR_LEN], 99 const uint8_t [IEEE80211_ADDR_LEN], 100 struct ieee80211_meshprep_ie *); 101static void hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *, 102 const struct ieee80211_frame *, 103 const struct ieee80211_meshperr_ie *); 104static int hwmp_send_perr(struct ieee80211_node *, 105 const uint8_t [IEEE80211_ADDR_LEN], 106 const uint8_t [IEEE80211_ADDR_LEN], 107 struct ieee80211_meshperr_ie *); 108static void hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *, 109 const struct ieee80211_frame *, 110 const struct ieee80211_meshrann_ie *); 111static int hwmp_send_rann(struct ieee80211_node *, 112 const uint8_t [IEEE80211_ADDR_LEN], 113 const uint8_t [IEEE80211_ADDR_LEN], 114 struct ieee80211_meshrann_ie *); 115static struct ieee80211_node * 116 hwmp_discover(struct ieee80211vap *, 117 const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *); 118static void hwmp_peerdown(struct ieee80211_node *); 119 120static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 }; 121static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 }; 122 123/* unalligned little endian access */ 124#define LE_WRITE_2(p, v) do { \ 125 ((uint8_t *)(p))[0] = (v) & 0xff; \ 126 ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 127} while (0) 128#define LE_WRITE_4(p, v) do { \ 129 ((uint8_t *)(p))[0] = (v) & 0xff; \ 130 ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 131 ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 132 ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 133} while (0) 134 135 136/* NB: the Target Address set in a Proactive PREQ is the broadcast address. */ 137static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] = 138 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 139 140typedef uint32_t ieee80211_hwmp_seq; 141#define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0) 142#define HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0) 143#define HWMP_SEQ_EQ(a, b) ((int32_t)((a)-(b)) == 0) 144#define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0) 145#define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0) 146 147#define HWMP_SEQ_MAX(a, b) (a > b ? a : b) 148 149/* 150 * Private extension of ieee80211_mesh_route. 151 */ 152struct ieee80211_hwmp_route { 153 ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/ 154 ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */ 155 ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/ 156 struct timeval hr_lastpreq; /* last time we sent a PREQ */ 157 int hr_preqretries; /* number of discoveries */ 158 int hr_lastdiscovery; /* last discovery in ticks */ 159}; 160struct ieee80211_hwmp_state { 161 ieee80211_hwmp_seq hs_seq; /* next seq to be used */ 162 ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */ 163 int hs_rootmode; /* proactive HWMP */ 164 struct timeval hs_lastperr; /* last time we sent a PERR */ 165 struct callout hs_roottimer; 166 uint8_t hs_maxhops; /* max hop count */ 167}; 168 169static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, 170 "IEEE 802.11s HWMP parameters"); 171static int ieee80211_hwmp_targetonly = 0; 172SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, 173 &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs"); 174static int ieee80211_hwmp_replyforward = 1; 175SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW, 176 &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs"); 177static int ieee80211_hwmp_pathtimeout = -1; 178SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW, 179 &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 180 "path entry lifetime (ms)"); 181static int ieee80211_hwmp_maxpreq_retries = -1; 182SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, maxpreq_retries, CTLTYPE_INT | CTLFLAG_RW, 183 &ieee80211_hwmp_maxpreq_retries, 0, ieee80211_sysctl_msecs_ticks, "I", 184 "maximum number of preq retries"); 185static int ieee80211_hwmp_net_diameter_traversaltime = -1; 186SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, net_diameter_traversal_time, 187 CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_net_diameter_traversaltime, 0, 188 ieee80211_sysctl_msecs_ticks, "I", 189 "estimate travelse time across the MBSS (ms)"); 190static int ieee80211_hwmp_roottimeout = -1; 191SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW, 192 &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 193 "root PREQ timeout (ms)"); 194static int ieee80211_hwmp_rootint = -1; 195SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW, 196 &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I", 197 "root interval (ms)"); 198static int ieee80211_hwmp_rannint = -1; 199SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW, 200 &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I", 201 "root announcement interval (ms)"); 202 203#define IEEE80211_HWMP_DEFAULT_MAXHOPS 31 204 205static ieee80211_recv_action_func hwmp_recv_action_meshpath; 206 207static struct ieee80211_mesh_proto_path mesh_proto_hwmp = { 208 .mpp_descr = "HWMP", 209 .mpp_ie = IEEE80211_MESHCONF_PATH_HWMP, 210 .mpp_discover = hwmp_discover, 211 .mpp_peerdown = hwmp_peerdown, 212 .mpp_vattach = hwmp_vattach, 213 .mpp_vdetach = hwmp_vdetach, 214 .mpp_newstate = hwmp_newstate, 215 .mpp_privlen = sizeof(struct ieee80211_hwmp_route), 216}; 217SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW, 218 &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I", 219 "mesh route inactivity timeout (ms)"); 220 221 222static void 223ieee80211_hwmp_init(void) 224{ 225 /* Default values as per amendment */ 226 ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000); 227 ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000); 228 ieee80211_hwmp_rootint = msecs_to_ticks(2*1000); 229 ieee80211_hwmp_rannint = msecs_to_ticks(1*1000); 230 ieee80211_hwmp_maxpreq_retries = 3; 231 /* 232 * (TU): A measurement of time equal to 1024 ��s, 233 * 500 TU is 512 ms. 234 */ 235 ieee80211_hwmp_net_diameter_traversaltime = msecs_to_ticks(512); 236 237 /* 238 * Register action frame handler. 239 */ 240 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH, 241 IEEE80211_ACTION_MESH_HWMP, hwmp_recv_action_meshpath); 242 243 /* NB: default is 5 secs per spec */ 244 mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000); 245 246 /* 247 * Register HWMP. 248 */ 249 ieee80211_mesh_register_proto_path(&mesh_proto_hwmp); 250} 251SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL); 252 253void 254hwmp_vattach(struct ieee80211vap *vap) 255{ 256 struct ieee80211_hwmp_state *hs; 257 258 KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 259 ("not a mesh vap, opmode %d", vap->iv_opmode)); 260 261 hs = malloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP, 262 M_NOWAIT | M_ZERO); 263 if (hs == NULL) { 264 printf("%s: couldn't alloc HWMP state\n", __func__); 265 return; 266 } 267 hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS; 268 callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE); 269 vap->iv_hwmp = hs; 270} 271 272void 273hwmp_vdetach(struct ieee80211vap *vap) 274{ 275 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 276 277 callout_drain(&hs->hs_roottimer); 278 free(vap->iv_hwmp, M_80211_VAP); 279 vap->iv_hwmp = NULL; 280} 281 282int 283hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg) 284{ 285 enum ieee80211_state nstate = vap->iv_state; 286 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 287 288 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", 289 __func__, ieee80211_state_name[ostate], 290 ieee80211_state_name[nstate], arg); 291 292 if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) 293 callout_drain(&hs->hs_roottimer); 294 if (nstate == IEEE80211_S_RUN) 295 hwmp_rootmode_setup(vap); 296 return 0; 297} 298 299/* 300 * Verify the length of an HWMP PREQ and return the number 301 * of destinations >= 1, if verification fails -1 is returned. 302 */ 303static int 304verify_mesh_preq_len(struct ieee80211vap *vap, 305 const struct ieee80211_frame *wh, const uint8_t *iefrm) 306{ 307 int alloc_sz = -1; 308 int ndest = -1; 309 if (iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE) { 310 /* Originator External Address present */ 311 alloc_sz = IEEE80211_MESHPREQ_BASE_SZ_AE; 312 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET_AE]; 313 } else { 314 /* w/o Originator External Address */ 315 alloc_sz = IEEE80211_MESHPREQ_BASE_SZ; 316 ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET]; 317 } 318 alloc_sz += ndest * IEEE80211_MESHPREQ_TRGT_SZ; 319 320 if(iefrm[1] != (alloc_sz)) { 321 IEEE80211_DISCARD(vap, 322 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 323 wh, NULL, "PREQ (AE=%s) with wrong len", 324 iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE ? "1" : "0"); 325 return (-1); 326 } 327 return ndest; 328} 329 330/* 331 * Verify the length of an HWMP PREP and returns 1 on success, 332 * otherwise -1. 333 */ 334static int 335verify_mesh_prep_len(struct ieee80211vap *vap, 336 const struct ieee80211_frame *wh, const uint8_t *iefrm) 337{ 338 int alloc_sz = -1; 339 if (iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE) { 340 if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ_AE) 341 alloc_sz = IEEE80211_MESHPREP_BASE_SZ_AE; 342 } else if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ) 343 alloc_sz = IEEE80211_MESHPREP_BASE_SZ; 344 if(alloc_sz < 0) { 345 IEEE80211_DISCARD(vap, 346 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 347 wh, NULL, "PREP (AE=%s) with wrong len", 348 iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE ? "1" : "0"); 349 return (-1); 350 } 351 return (1); 352} 353 354/* 355 * Verify the length of an HWMP PERR and return the number 356 * of destinations >= 1, if verification fails -1 is returned. 357 */ 358static int 359verify_mesh_perr_len(struct ieee80211vap *vap, 360 const struct ieee80211_frame *wh, const uint8_t *iefrm) 361{ 362 int alloc_sz = -1; 363 const uint8_t *iefrm_t = iefrm; 364 uint8_t ndest = iefrm_t[IEEE80211_MESHPERR_NDEST_OFFSET]; 365 int i; 366 367 if(ndest > IEEE80211_MESHPERR_MAXDEST) { 368 IEEE80211_DISCARD(vap, 369 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 370 wh, NULL, "PERR with wrong number of destionat (>19), %u", 371 ndest); 372 return (-1); 373 } 374 375 iefrm_t += IEEE80211_MESHPERR_NDEST_OFFSET + 1; /* flag is next field */ 376 /* We need to check each destionation flag to know size */ 377 for(i = 0; i<ndest; i++) { 378 if ((*iefrm_t) & IEEE80211_MESHPERR_FLAGS_AE) 379 iefrm_t += IEEE80211_MESHPERR_DEST_SZ_AE; 380 else 381 iefrm_t += IEEE80211_MESHPERR_DEST_SZ; 382 } 383 384 alloc_sz = (iefrm_t - iefrm) - 2; /* action + code */ 385 if(alloc_sz != iefrm[1]) { 386 IEEE80211_DISCARD(vap, 387 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 388 wh, NULL, "%s", "PERR with wrong len"); 389 return (-1); 390 } 391 return ndest; 392} 393 394static int 395hwmp_recv_action_meshpath(struct ieee80211_node *ni, 396 const struct ieee80211_frame *wh, 397 const uint8_t *frm, const uint8_t *efrm) 398{ 399 struct ieee80211vap *vap = ni->ni_vap; 400 struct ieee80211_meshpreq_ie *preq; 401 struct ieee80211_meshprep_ie *prep; 402 struct ieee80211_meshperr_ie *perr; 403 struct ieee80211_meshrann_ie rann; 404 const uint8_t *iefrm = frm + 2; /* action + code */ 405 const uint8_t *iefrm_t = iefrm; /* temporary pointer */ 406 int ndest = -1; 407 int found = 0; 408 409 while (efrm - iefrm > 1) { 410 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0); 411 switch (*iefrm) { 412 case IEEE80211_ELEMID_MESHPREQ: 413 { 414 int i = 0; 415 416 iefrm_t = iefrm; 417 ndest = verify_mesh_preq_len(vap, wh, iefrm_t); 418 if (ndest < 0) { 419 vap->iv_stats.is_rx_mgtdiscard++; 420 break; 421 } 422 preq = malloc(sizeof(*preq) + 423 (ndest - 1) * sizeof(*preq->preq_targets), 424 M_80211_MESH_PREQ, M_NOWAIT | M_ZERO); 425 KASSERT(preq != NULL, ("preq == NULL")); 426 427 preq->preq_ie = *iefrm_t++; 428 preq->preq_len = *iefrm_t++; 429 preq->preq_flags = *iefrm_t++; 430 preq->preq_hopcount = *iefrm_t++; 431 preq->preq_ttl = *iefrm_t++; 432 preq->preq_id = LE_READ_4(iefrm_t); iefrm_t += 4; 433 IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm_t); 434 iefrm_t += 6; 435 preq->preq_origseq = LE_READ_4(iefrm_t); iefrm_t += 4; 436 /* NB: may have Originator Proxied Address */ 437 if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) { 438 IEEE80211_ADDR_COPY( 439 preq->preq_orig_ext_addr, iefrm_t); 440 iefrm_t += 6; 441 } 442 preq->preq_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4; 443 preq->preq_metric = LE_READ_4(iefrm_t); iefrm_t += 4; 444 preq->preq_tcount = *iefrm_t++; 445 446 for (i = 0; i < preq->preq_tcount; i++) { 447 preq->preq_targets[i].target_flags = *iefrm_t++; 448 IEEE80211_ADDR_COPY( 449 preq->preq_targets[i].target_addr, iefrm_t); 450 iefrm_t += 6; 451 preq->preq_targets[i].target_seq = 452 LE_READ_4(iefrm_t); 453 iefrm_t += 4; 454 } 455 456 hwmp_recv_preq(vap, ni, wh, preq); 457 free(preq, M_80211_MESH_PREQ); 458 found++; 459 break; 460 } 461 case IEEE80211_ELEMID_MESHPREP: 462 { 463 iefrm_t = iefrm; 464 ndest = verify_mesh_prep_len(vap, wh, iefrm_t); 465 if (ndest < 0) { 466 vap->iv_stats.is_rx_mgtdiscard++; 467 break; 468 } 469 prep = malloc(sizeof(*prep), 470 M_80211_MESH_PREP, M_NOWAIT | M_ZERO); 471 KASSERT(prep != NULL, ("prep == NULL")); 472 473 prep->prep_ie = *iefrm_t++; 474 prep->prep_len = *iefrm_t++; 475 prep->prep_flags = *iefrm_t++; 476 prep->prep_hopcount = *iefrm_t++; 477 prep->prep_ttl = *iefrm_t++; 478 IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm_t); 479 iefrm_t += 6; 480 prep->prep_targetseq = LE_READ_4(iefrm_t); iefrm_t += 4; 481 /* NB: May have Target Proxied Address */ 482 if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) { 483 IEEE80211_ADDR_COPY( 484 prep->prep_target_ext_addr, iefrm_t); 485 iefrm_t += 6; 486 } 487 prep->prep_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4; 488 prep->prep_metric = LE_READ_4(iefrm_t); iefrm_t += 4; 489 IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm_t); 490 iefrm_t += 6; 491 prep->prep_origseq = LE_READ_4(iefrm_t); iefrm_t += 4; 492 493 hwmp_recv_prep(vap, ni, wh, prep); 494 free(prep, M_80211_MESH_PREP); 495 found++; 496 break; 497 } 498 case IEEE80211_ELEMID_MESHPERR: 499 { 500 int i = 0; 501 502 iefrm_t = iefrm; 503 ndest = verify_mesh_perr_len(vap, wh, iefrm_t); 504 if (ndest < 0) { 505 vap->iv_stats.is_rx_mgtdiscard++; 506 break; 507 } 508 perr = malloc(sizeof(*perr) + 509 (ndest - 1) * sizeof(*perr->perr_dests), 510 M_80211_MESH_PERR, M_NOWAIT | M_ZERO); 511 KASSERT(perr != NULL, ("perr == NULL")); 512 513 perr->perr_ie = *iefrm_t++; 514 perr->perr_len = *iefrm_t++; 515 perr->perr_ttl = *iefrm_t++; 516 perr->perr_ndests = *iefrm_t++; 517 518 for (i = 0; i<perr->perr_ndests; i++) { 519 perr->perr_dests[i].dest_flags = *iefrm_t++; 520 IEEE80211_ADDR_COPY( 521 perr->perr_dests[i].dest_addr, iefrm_t); 522 iefrm_t += 6; 523 perr->perr_dests[i].dest_seq = LE_READ_4(iefrm_t); 524 iefrm_t += 4; 525 /* NB: May have Target Proxied Address */ 526 if (perr->perr_dests[i].dest_flags & 527 IEEE80211_MESHPERR_FLAGS_AE) { 528 IEEE80211_ADDR_COPY( 529 perr->perr_dests[i].dest_ext_addr, 530 iefrm_t); 531 iefrm_t += 6; 532 } 533 perr->perr_dests[i].dest_rcode = 534 LE_READ_2(iefrm_t); 535 iefrm_t += 2; 536 } 537 538 hwmp_recv_perr(vap, ni, wh, perr); 539 free(perr, M_80211_MESH_PERR); 540 found++; 541 break; 542 } 543 case IEEE80211_ELEMID_MESHRANN: 544 { 545 const struct ieee80211_meshrann_ie *mrann = 546 (const struct ieee80211_meshrann_ie *) iefrm; 547 if (mrann->rann_len != 548 sizeof(struct ieee80211_meshrann_ie) - 2) { 549 IEEE80211_DISCARD(vap, 550 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 551 wh, NULL, "%s", "RAN with wrong len"); 552 vap->iv_stats.is_rx_mgtdiscard++; 553 return 1; 554 } 555 memcpy(&rann, mrann, sizeof(rann)); 556 rann.rann_seq = LE_READ_4(&mrann->rann_seq); 557 rann.rann_metric = LE_READ_4(&mrann->rann_metric); 558 hwmp_recv_rann(vap, ni, wh, &rann); 559 found++; 560 break; 561 } 562 } 563 iefrm += iefrm[1] + 2; 564 } 565 if (!found) { 566 IEEE80211_DISCARD(vap, 567 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 568 wh, NULL, "%s", "PATH SEL action without IE"); 569 vap->iv_stats.is_rx_mgtdiscard++; 570 } 571 return 0; 572} 573 574static int 575hwmp_send_action(struct ieee80211_node *ni, 576 const uint8_t sa[IEEE80211_ADDR_LEN], 577 const uint8_t da[IEEE80211_ADDR_LEN], 578 uint8_t *ie, size_t len) 579{ 580 struct ieee80211vap *vap = ni->ni_vap; 581 struct ieee80211com *ic = ni->ni_ic; 582 struct ieee80211_bpf_params params; 583 struct mbuf *m; 584 uint8_t *frm; 585 586 if (vap->iv_state == IEEE80211_S_CAC) { 587 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 588 "block %s frame in CAC state", "HWMP action"); 589 vap->iv_stats.is_tx_badstate++; 590 return EIO; /* XXX */ 591 } 592 593 KASSERT(ni != NULL, ("null node")); 594 /* 595 * Hold a reference on the node so it doesn't go away until after 596 * the xmit is complete all the way in the driver. On error we 597 * will remove our reference. 598 */ 599#ifdef IEEE80211_DEBUG_REFCNT 600 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 601 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 602 __func__, __LINE__, 603 ni, ether_sprintf(ni->ni_macaddr), 604 ieee80211_node_refcnt(ni)+1); 605#endif 606 ieee80211_ref_node(ni); 607 608 m = ieee80211_getmgtframe(&frm, 609 ic->ic_headroom + sizeof(struct ieee80211_frame), 610 sizeof(struct ieee80211_action) + len 611 ); 612 if (m == NULL) { 613 ieee80211_free_node(ni); 614 vap->iv_stats.is_tx_nobuf++; 615 return ENOMEM; 616 } 617 *frm++ = IEEE80211_ACTION_CAT_MESH; 618 *frm++ = IEEE80211_ACTION_MESH_HWMP; 619 switch (*ie) { 620 case IEEE80211_ELEMID_MESHPREQ: 621 frm = hwmp_add_meshpreq(frm, 622 (struct ieee80211_meshpreq_ie *)ie); 623 break; 624 case IEEE80211_ELEMID_MESHPREP: 625 frm = hwmp_add_meshprep(frm, 626 (struct ieee80211_meshprep_ie *)ie); 627 break; 628 case IEEE80211_ELEMID_MESHPERR: 629 frm = hwmp_add_meshperr(frm, 630 (struct ieee80211_meshperr_ie *)ie); 631 break; 632 case IEEE80211_ELEMID_MESHRANN: 633 frm = hwmp_add_meshrann(frm, 634 (struct ieee80211_meshrann_ie *)ie); 635 break; 636 } 637 638 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 639 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 640 if (m == NULL) { 641 ieee80211_free_node(ni); 642 vap->iv_stats.is_tx_nobuf++; 643 return ENOMEM; 644 } 645 ieee80211_send_setup(ni, m, 646 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION, 647 IEEE80211_NONQOS_TID, sa, da, sa); 648 649 m->m_flags |= M_ENCAP; /* mark encapsulated */ 650 IEEE80211_NODE_STAT(ni, tx_mgmt); 651 652 memset(¶ms, 0, sizeof(params)); 653 params.ibp_pri = WME_AC_VO; 654 params.ibp_rate0 = ni->ni_txparms->mgmtrate; 655 if (IEEE80211_IS_MULTICAST(da)) 656 params.ibp_try0 = 1; 657 else 658 params.ibp_try0 = ni->ni_txparms->maxretry; 659 params.ibp_power = ni->ni_txpower; 660 return ic->ic_raw_xmit(ni, m, ¶ms); 661} 662 663#define ADDSHORT(frm, v) do { \ 664 frm[0] = (v) & 0xff; \ 665 frm[1] = (v) >> 8; \ 666 frm += 2; \ 667} while (0) 668#define ADDWORD(frm, v) do { \ 669 LE_WRITE_4(frm, v); \ 670 frm += 4; \ 671} while (0) 672/* 673 * Add a Mesh Path Request IE to a frame. 674 */ 675#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags 676#define PREQ_TADDR(n) preq->preq_targets[n].target_addr 677#define PREQ_TSEQ(n) preq->preq_targets[n].target_seq 678static uint8_t * 679hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq) 680{ 681 int i; 682 683 *frm++ = IEEE80211_ELEMID_MESHPREQ; 684 *frm++ = preq->preq_len; /* len already calculated */ 685 *frm++ = preq->preq_flags; 686 *frm++ = preq->preq_hopcount; 687 *frm++ = preq->preq_ttl; 688 ADDWORD(frm, preq->preq_id); 689 IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6; 690 ADDWORD(frm, preq->preq_origseq); 691 if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) { 692 IEEE80211_ADDR_COPY(frm, preq->preq_orig_ext_addr); 693 frm += 6; 694 } 695 ADDWORD(frm, preq->preq_lifetime); 696 ADDWORD(frm, preq->preq_metric); 697 *frm++ = preq->preq_tcount; 698 for (i = 0; i < preq->preq_tcount; i++) { 699 *frm++ = PREQ_TFLAGS(i); 700 IEEE80211_ADDR_COPY(frm, PREQ_TADDR(i)); 701 frm += 6; 702 ADDWORD(frm, PREQ_TSEQ(i)); 703 } 704 return frm; 705} 706#undef PREQ_TFLAGS 707#undef PREQ_TADDR 708#undef PREQ_TSEQ 709 710/* 711 * Add a Mesh Path Reply IE to a frame. 712 */ 713static uint8_t * 714hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep) 715{ 716 *frm++ = IEEE80211_ELEMID_MESHPREP; 717 *frm++ = prep->prep_len; /* len already calculated */ 718 *frm++ = prep->prep_flags; 719 *frm++ = prep->prep_hopcount; 720 *frm++ = prep->prep_ttl; 721 IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6; 722 ADDWORD(frm, prep->prep_targetseq); 723 if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) { 724 IEEE80211_ADDR_COPY(frm, prep->prep_target_ext_addr); 725 frm += 6; 726 } 727 ADDWORD(frm, prep->prep_lifetime); 728 ADDWORD(frm, prep->prep_metric); 729 IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6; 730 ADDWORD(frm, prep->prep_origseq); 731 return frm; 732} 733 734/* 735 * Add a Mesh Path Error IE to a frame. 736 */ 737#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags 738#define PERR_DADDR(n) perr->perr_dests[n].dest_addr 739#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq 740#define PERR_EXTADDR(n) perr->perr_dests[n].dest_ext_addr 741#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode 742static uint8_t * 743hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr) 744{ 745 int i; 746 747 *frm++ = IEEE80211_ELEMID_MESHPERR; 748 *frm++ = perr->perr_len; /* len already calculated */ 749 *frm++ = perr->perr_ttl; 750 *frm++ = perr->perr_ndests; 751 for (i = 0; i < perr->perr_ndests; i++) { 752 *frm++ = PERR_DFLAGS(i); 753 IEEE80211_ADDR_COPY(frm, PERR_DADDR(i)); 754 frm += 6; 755 ADDWORD(frm, PERR_DSEQ(i)); 756 if (PERR_DFLAGS(i) & IEEE80211_MESHPERR_FLAGS_AE) { 757 IEEE80211_ADDR_COPY(frm, PERR_EXTADDR(i)); 758 frm += 6; 759 } 760 ADDSHORT(frm, PERR_DRCODE(i)); 761 } 762 return frm; 763} 764#undef PERR_DFLAGS 765#undef PERR_DADDR 766#undef PERR_DSEQ 767#undef PERR_EXTADDR 768#undef PERR_DRCODE 769 770/* 771 * Add a Root Annoucement IE to a frame. 772 */ 773static uint8_t * 774hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann) 775{ 776 *frm++ = IEEE80211_ELEMID_MESHRANN; 777 *frm++ = rann->rann_len; 778 *frm++ = rann->rann_flags; 779 *frm++ = rann->rann_hopcount; 780 *frm++ = rann->rann_ttl; 781 IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6; 782 ADDWORD(frm, rann->rann_seq); 783 ADDWORD(frm, rann->rann_interval); 784 ADDWORD(frm, rann->rann_metric); 785 return frm; 786} 787 788static void 789hwmp_rootmode_setup(struct ieee80211vap *vap) 790{ 791 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 792 793 switch (hs->hs_rootmode) { 794 case IEEE80211_HWMP_ROOTMODE_DISABLED: 795 callout_drain(&hs->hs_roottimer); 796 break; 797 case IEEE80211_HWMP_ROOTMODE_NORMAL: 798 case IEEE80211_HWMP_ROOTMODE_PROACTIVE: 799 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint, 800 hwmp_rootmode_cb, vap); 801 break; 802 case IEEE80211_HWMP_ROOTMODE_RANN: 803 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint, 804 hwmp_rootmode_rann_cb, vap); 805 break; 806 } 807} 808 809/* 810 * Send a broadcast Path Request to find all nodes on the mesh. We are 811 * called when the vap is configured as a HWMP root node. 812 */ 813#define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 814#define PREQ_TADDR(n) preq.preq_targets[n].target_addr 815#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 816static void 817hwmp_rootmode_cb(void *arg) 818{ 819 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 820 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 821 struct ieee80211_mesh_state *ms = vap->iv_mesh; 822 struct ieee80211_meshpreq_ie preq; 823 824 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 825 "%s", "send broadcast PREQ"); 826 827 preq.preq_flags = 0; 828 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 829 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR; 830 if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE) 831 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP; 832 preq.preq_hopcount = 0; 833 preq.preq_ttl = ms->ms_ttl; 834 preq.preq_id = ++hs->hs_preqid; 835 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 836 preq.preq_origseq = ++hs->hs_seq; 837 preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout); 838 preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 839 preq.preq_tcount = 1; 840 IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr); 841 PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO | 842 IEEE80211_MESHPREQ_TFLAGS_RF; 843 PREQ_TSEQ(0) = 0; 844 vap->iv_stats.is_hwmp_rootreqs++; 845 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq, 846 NULL, NULL); /* NB: we enforce rate check ourself */ 847 hwmp_rootmode_setup(vap); 848} 849#undef PREQ_TFLAGS 850#undef PREQ_TADDR 851#undef PREQ_TSEQ 852 853/* 854 * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are 855 * called when the vap is configured as a HWMP RANN root node. 856 */ 857static void 858hwmp_rootmode_rann_cb(void *arg) 859{ 860 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 861 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 862 struct ieee80211_mesh_state *ms = vap->iv_mesh; 863 struct ieee80211_meshrann_ie rann; 864 865 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 866 "%s", "send broadcast RANN"); 867 868 rann.rann_flags = 0; 869 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 870 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR; 871 rann.rann_hopcount = 0; 872 rann.rann_ttl = ms->ms_ttl; 873 IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr); 874 rann.rann_seq = ++hs->hs_seq; 875 rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 876 877 vap->iv_stats.is_hwmp_rootrann++; 878 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann); 879 hwmp_rootmode_setup(vap); 880} 881 882#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags 883#define PREQ_TADDR(n) preq->preq_targets[n].target_addr 884#define PREQ_TSEQ(n) preq->preq_targets[n].target_seq 885static void 886hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, 887 const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq) 888{ 889 struct ieee80211_mesh_state *ms = vap->iv_mesh; 890 struct ieee80211_mesh_route *rt = NULL; /* pro-active code */ 891 struct ieee80211_mesh_route *rtorig = NULL; 892 struct ieee80211_mesh_route *rttarg = NULL; 893 struct ieee80211_hwmp_route *hrorig = NULL; 894 struct ieee80211_hwmp_route *hrtarg = NULL; 895 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 896 struct ieee80211_meshprep_ie prep; 897 898 if (ni == vap->iv_bss || 899 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 900 return; 901 /* 902 * Ignore PREQs from us. Could happen because someone forward it 903 * back to us. 904 */ 905 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr)) 906 return; 907 908 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 909 "received PREQ, orig %6D, targ(0) %6D", preq->preq_origaddr, ":", 910 PREQ_TADDR(0), ":"); 911 912 /* 913 * Acceptance criteria: if the PREQ is not for us or not broadcast 914 * AND forwarding is disabled, discard this PREQ. 915 * XXX: need to check PROXY 916 */ 917 if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) || 918 !IEEE80211_IS_MULTICAST(PREQ_TADDR(0))) && 919 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 920 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 921 preq->preq_origaddr, NULL, "%s", "not accepting PREQ"); 922 return; 923 } 924 /* 925 * Acceptance criteria: if unicast addressed 926 * AND no valid forwarding for Target of PREQ, discard this PREQ. 927 */ 928 rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); 929 if(rttarg != NULL) 930 hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg, 931 struct ieee80211_hwmp_route); 932 /* Address mode: ucast */ 933 if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 && 934 rttarg == NULL && 935 !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { 936 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 937 preq->preq_origaddr, NULL, 938 "unicast addressed PREQ of unknown target %6D", 939 PREQ_TADDR(0), ":"); 940 return; 941 } 942 943 /* PREQ ACCEPTED */ 944 945 rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); 946 if (rtorig == NULL) { 947 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr); 948 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 949 "adding originator %6D", preq->preq_origaddr, ":"); 950 } 951 if (rtorig == NULL) { 952 /* XXX stat */ 953 return; 954 } 955 hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route); 956 957 /* Data creation and update of forwarding information 958 * according to Table 11C-8 for originator mesh STA. 959 */ 960 if (HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) || 961 (HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) && 962 preq->preq_metric < rtorig->rt_metric)) { 963 hrorig->hr_seq = preq->preq_origseq; 964 IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2); 965 rtorig->rt_metric = preq->preq_metric + 966 ms->ms_pmetric->mpm_metric(ni); 967 rtorig->rt_nhops = preq->preq_hopcount + 1; 968 ieee80211_mesh_rt_update(rtorig, preq->preq_lifetime); 969 /* path to orig is valid now */ 970 rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 971 }else if(hrtarg != NULL && 972 HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0)) && 973 (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { 974 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 975 "discard PREQ from %6D, old seq no %u <= %u", 976 preq->preq_origaddr, ":", 977 preq->preq_origseq, hrorig->hr_seq); 978 return; 979 } 980 981 /* 982 * Forwarding information for transmitter mesh STA 983 * [OPTIONAL: if metric improved] 984 */ 985 986 /* 987 * Check if the PREQ is addressed to us. 988 * or a Proxy currently supplied by us. 989 */ 990 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) || 991 (rttarg != NULL && 992 rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY && 993 rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { 994 /* 995 * When we are the target we shall update our own HWMP seq 996 * number with max of (current and preq->seq) + 1 997 */ 998 hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1; 999 1000 prep.prep_flags = 0; 1001 if (rttarg != NULL && /* if NULL it means we are the target */ 1002 rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 1003 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1004 "reply for proxy %6D", rttarg->rt_dest, ":"); 1005 prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE; 1006 IEEE80211_ADDR_COPY(prep.prep_target_ext_addr, 1007 rttarg->rt_dest); 1008 /* update proxy seqno to HWMP seqno */ 1009 rttarg->rt_ext_seq = hs->hs_seq; 1010 } 1011 /* 1012 * Build and send a PREP frame. 1013 */ 1014 prep.prep_hopcount = 0; 1015 prep.prep_ttl = ms->ms_ttl; 1016 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr); 1017 prep.prep_targetseq = hs->hs_seq; 1018 prep.prep_lifetime = preq->preq_lifetime; 1019 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 1020 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr); 1021 prep.prep_origseq = preq->preq_origseq; 1022 1023 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1024 "reply to %6D", preq->preq_origaddr, ":"); 1025 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep); 1026 return; 1027 } 1028 /* 1029 * Proactive PREQ: reply with a proactive PREP to the 1030 * root STA if requested. 1031 */ 1032 if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) && 1033 (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) { 1034 uint8_t rootmac[IEEE80211_ADDR_LEN]; 1035 1036 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr); 1037 rt = ieee80211_mesh_rt_find(vap, rootmac); 1038 if (rt == NULL) { 1039 rt = ieee80211_mesh_rt_add(vap, rootmac); 1040 if (rt == NULL) { 1041 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1042 "unable to add root mesh path to %6D", 1043 rootmac, ":"); 1044 vap->iv_stats.is_mesh_rtaddfailed++; 1045 return; 1046 } 1047 } 1048 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1049 "root mesh station @ %6D", rootmac, ":"); 1050 1051 /* 1052 * Reply with a PREP if we don't have a path to the root 1053 * or if the root sent us a proactive PREQ. 1054 */ 1055 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || 1056 (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) { 1057 prep.prep_flags = 0; 1058 prep.prep_hopcount = 0; 1059 prep.prep_ttl = ms->ms_ttl; 1060 IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac); 1061 prep.prep_origseq = preq->preq_origseq; 1062 prep.prep_lifetime = preq->preq_lifetime; 1063 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 1064 IEEE80211_ADDR_COPY(prep.prep_targetaddr, 1065 vap->iv_myaddr); 1066 prep.prep_targetseq = ++hs->hs_seq; 1067 hwmp_send_prep(vap->iv_bss, vap->iv_myaddr, 1068 broadcastaddr, &prep); 1069 } 1070 hwmp_discover(vap, rootmac, NULL); 1071 return; 1072 } 1073 1074 /* 1075 * Forwarding and Intermediate reply for PREQs with 1 target. 1076 */ 1077 if (preq->preq_tcount == 1) { 1078 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */ 1079 1080 memcpy(&ppreq, preq, sizeof(ppreq)); 1081 /* 1082 * We have a valid route to this node. 1083 */ 1084 if (rttarg != NULL && 1085 (rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { 1086 if (preq->preq_ttl > 1 && 1087 preq->preq_hopcount < hs->hs_maxhops) { 1088 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1089 "forward PREQ from %6D", 1090 preq->preq_origaddr, ":"); 1091 /* 1092 * Propagate the original PREQ. 1093 * PREQ is unicast now to rttarg->rt_nexthop 1094 */ 1095 ppreq.preq_flags |= 1096 IEEE80211_MESHPREQ_FLAGS_AM; 1097 ppreq.preq_hopcount += 1; 1098 ppreq.preq_ttl -= 1; 1099 ppreq.preq_metric += 1100 ms->ms_pmetric->mpm_metric(ni); 1101 /* 1102 * Set TO and unset RF bits because we are 1103 * going to send a PREP next. 1104 */ 1105 ppreq.preq_targets[0].target_flags |= 1106 IEEE80211_MESHPREQ_TFLAGS_TO; 1107 ppreq.preq_targets[0].target_flags &= 1108 ~IEEE80211_MESHPREQ_TFLAGS_RF; 1109 hwmp_send_preq(ni, vap->iv_myaddr, 1110 rttarg->rt_nexthop, &ppreq, 1111 &hrtarg->hr_lastpreq, 1112 &ieee80211_hwmp_preqminint); 1113 } 1114 /* 1115 * Check if we can send an intermediate Path Reply, 1116 * i.e., Target Only bit is not set. 1117 */ 1118 if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO) && 1119 HWMP_SEQ_GEQ(hrtarg->hr_seq, PREQ_TSEQ(0))) { 1120 struct ieee80211_meshprep_ie prep; 1121 1122 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1123 "intermediate reply for PREQ from %6D", 1124 preq->preq_origaddr, ":"); 1125 prep.prep_flags = 0; 1126 prep.prep_hopcount = rttarg->rt_nhops; 1127 prep.prep_ttl = ms->ms_ttl; 1128 IEEE80211_ADDR_COPY(&prep.prep_targetaddr, 1129 PREQ_TADDR(0)); 1130 prep.prep_targetseq = hrtarg->hr_seq; 1131 prep.prep_lifetime = preq->preq_lifetime; 1132 prep.prep_metric =rttarg->rt_metric; 1133 IEEE80211_ADDR_COPY(&prep.prep_origaddr, 1134 preq->preq_origaddr); 1135 prep.prep_origseq = hrorig->hr_seq; 1136 hwmp_send_prep(ni, vap->iv_myaddr, 1137 rtorig->rt_nexthop, &prep); 1138 } 1139 /* 1140 * We have no information about this path, 1141 * propagate the PREQ. 1142 */ 1143 } else if (preq->preq_ttl > 1 && 1144 preq->preq_hopcount < hs->hs_maxhops) { 1145 if (rttarg == NULL) { 1146 rttarg = 1147 ieee80211_mesh_rt_add(vap, PREQ_TADDR(0)); 1148 if (rttarg == NULL) { 1149 IEEE80211_NOTE(vap, 1150 IEEE80211_MSG_HWMP, ni, 1151 "unable to add PREQ path to %6D", 1152 PREQ_TADDR(0), ":"); 1153 vap->iv_stats.is_mesh_rtaddfailed++; 1154 return; 1155 } 1156 } 1157 rttarg->rt_metric = preq->preq_metric; 1158 ieee80211_mesh_rt_update(rttarg, preq->preq_lifetime); 1159 hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg, 1160 struct ieee80211_hwmp_route); 1161 hrtarg->hr_seq = PREQ_TSEQ(0); 1162 hrtarg->hr_preqid = preq->preq_id; 1163 1164 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1165 "forward PREQ from %6D", 1166 preq->preq_origaddr, ":"); 1167 ppreq.preq_hopcount += 1; 1168 ppreq.preq_ttl -= 1; 1169 ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); 1170 hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr, 1171 &ppreq, &hrtarg->hr_lastpreq, 1172 &ieee80211_hwmp_preqminint); 1173 } 1174 } 1175} 1176#undef PREQ_TFLAGS 1177#undef PREQ_TADDR 1178#undef PREQ_TSEQ 1179 1180static int 1181hwmp_send_preq(struct ieee80211_node *ni, 1182 const uint8_t sa[IEEE80211_ADDR_LEN], 1183 const uint8_t da[IEEE80211_ADDR_LEN], 1184 struct ieee80211_meshpreq_ie *preq, 1185 struct timeval *last, struct timeval *minint) 1186{ 1187 1188 /* 1189 * Enforce PREQ interval. 1190 * NB: Proactive ROOT PREQs rate is handled by cb task. 1191 */ 1192 if (last != NULL && minint != NULL) { 1193 if (ratecheck(last, minint) == 0) 1194 return EALREADY; /* XXX: we should postpone */ 1195 getmicrouptime(last); 1196 } 1197 1198 /* 1199 * mesh preq action frame format 1200 * [6] da 1201 * [6] sa 1202 * [6] addr3 = sa 1203 * [1] action 1204 * [1] category 1205 * [tlv] mesh path request 1206 */ 1207 preq->preq_ie = IEEE80211_ELEMID_MESHPREQ; 1208 preq->preq_len = (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE ? 1209 IEEE80211_MESHPREQ_BASE_SZ_AE : IEEE80211_MESHPREQ_BASE_SZ) + 1210 preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ; 1211 return hwmp_send_action(ni, sa, da, (uint8_t *)preq, preq->preq_len+2); 1212} 1213 1214static void 1215hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, 1216 const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep) 1217{ 1218#define IS_PROXY(rt) (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) 1219#define PROXIED_BY_US(rt) \ 1220 (IEEE80211_ADDR_EQ(vap->iv_myaddr, rt->rt_mesh_gate)) 1221 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1222 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1223 struct ieee80211_mesh_route *rt = NULL; 1224 struct ieee80211_mesh_route *rtorig = NULL; 1225 struct ieee80211_mesh_route *rtext = NULL; 1226 struct ieee80211_hwmp_route *hr; 1227 struct ieee80211com *ic = vap->iv_ic; 1228 struct ifnet *ifp = vap->iv_ifp; 1229 struct mbuf *m, *next; 1230 uint32_t metric = 0; 1231 const uint8_t *addr; 1232 1233 if (ni == vap->iv_bss || 1234 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 1235 return; 1236 1237 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1238 "received PREP, orig %6D, targ %6D", prep->prep_origaddr, ":", 1239 prep->prep_targetaddr, ":"); 1240 1241 /* 1242 * Acceptance criteria: (If the corresponding PREP was not generated 1243 * by us OR not generated by an external mac that is not proxied by us) 1244 * AND forwarding is disabled, discard this PREP. 1245 */ 1246 rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr); 1247 if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) || 1248 (rtorig != NULL && IS_PROXY(rtorig) && !PROXIED_BY_US(rtorig))) && 1249 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)){ 1250 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1251 "discard PREP, orig(%6D) not proxied or generated by us", 1252 prep->prep_origaddr, ":"); 1253 return; 1254 } 1255 1256 /* PREP ACCEPTED */ 1257 1258 /* 1259 * If accepted shall create or update the active forwarding information 1260 * it maintains for the target mesh STA of the PREP (according to the 1261 * rules defined in 13.10.8.4). If the conditions for creating or 1262 * updating the forwarding information have not been met in those 1263 * rules, no further steps are applied to the PREP. 1264 * [OPTIONAL]: update forwarding information to TA if metric improves. 1265 */ 1266 rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr); 1267 if (rt == NULL) { 1268 rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr); 1269 if (rt == NULL) { 1270 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1271 "unable to add PREP path to %6D", 1272 prep->prep_targetaddr, ":"); 1273 vap->iv_stats.is_mesh_rtaddfailed++; 1274 return; 1275 } 1276 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1277 "adding target %6D", prep->prep_targetaddr, ":"); 1278 } 1279 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1280 /* update path metric */ 1281 metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni); 1282 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { 1283 if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) { 1284 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1285 "discard PREP from %6D, old seq no %u < %u", 1286 prep->prep_targetaddr, ":", 1287 prep->prep_targetseq, hr->hr_seq); 1288 return; 1289 } else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) && 1290 metric > rt->rt_metric) { 1291 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1292 "discard PREP from %6D, new metric %u > %u", 1293 prep->prep_targetaddr, ":", 1294 prep->prep_metric, rt->rt_metric); 1295 return; 1296 } 1297 } 1298 1299 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1300 "%s path to %6D, hopcount %d:%d metric %d:%d", 1301 rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ? 1302 "prefer" : "update", 1303 prep->prep_targetaddr, ":", 1304 rt->rt_nhops, prep->prep_hopcount, 1305 rt->rt_metric, metric); 1306 1307 hr->hr_seq = prep->prep_targetseq; 1308 hr->hr_preqretries = 0; 1309 IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr); 1310 rt->rt_metric = metric; 1311 rt->rt_nhops = prep->prep_hopcount + 1; 1312 ieee80211_mesh_rt_update(rt, prep->prep_lifetime); 1313 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */ 1314 1315 /* 1316 * If it's NOT for us, propagate the PREP 1317 */ 1318 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && 1319 prep->prep_ttl > 1 && 1320 prep->prep_hopcount < hs->hs_maxhops) { 1321 struct ieee80211_meshprep_ie pprep; /* propagated PREP */ 1322 /* 1323 * NB: We should already have setup the path to orig 1324 * mesh STA when we propagated PREQ to target mesh STA, 1325 * no PREP is generated without a corresponding PREQ. 1326 * XXX: for now just ignore. 1327 */ 1328 if (rtorig == NULL) { 1329 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1330 "received PREP for an unknown orig(%6D)", 1331 prep->prep_origaddr, ":"); 1332 return; 1333 } 1334 1335 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1336 "propagate PREP from %6D", 1337 prep->prep_targetaddr, ":"); 1338 1339 memcpy(&pprep, prep, sizeof(pprep)); 1340 pprep.prep_hopcount += 1; 1341 pprep.prep_ttl -= 1; 1342 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni); 1343 hwmp_send_prep(ni, vap->iv_myaddr, rtorig->rt_nexthop, &pprep); 1344 1345 /* precursor list for the Target Mesh STA Address is updated */ 1346 } 1347 1348 /* 1349 * Check if we received a PREP w/ AE and store target external address. 1350 * We may store target external address if recevied PREP w/ AE 1351 * and we are not final destination 1352 */ 1353 if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) { 1354 rtext = ieee80211_mesh_rt_find(vap, 1355 prep->prep_target_ext_addr); 1356 if (rtext == NULL) { 1357 rtext = ieee80211_mesh_rt_add(vap, 1358 prep->prep_target_ext_addr); 1359 if (rtext == NULL) { 1360 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1361 "unable to add PREP path to proxy %6D", 1362 prep->prep_targetaddr, ":"); 1363 vap->iv_stats.is_mesh_rtaddfailed++; 1364 return; 1365 } 1366 } 1367 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1368 "%s path to %6D, hopcount %d:%d metric %d:%d", 1369 rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ? 1370 "prefer" : "update", 1371 prep->prep_target_ext_addr, ":", 1372 rtext->rt_nhops, prep->prep_hopcount, 1373 rtext->rt_metric, metric); 1374 1375 rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY | 1376 IEEE80211_MESHRT_FLAGS_VALID; 1377 IEEE80211_ADDR_COPY(rtext->rt_dest, 1378 prep->prep_target_ext_addr); 1379 IEEE80211_ADDR_COPY(rtext->rt_mesh_gate, 1380 prep->prep_targetaddr); 1381 IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2); 1382 rtext->rt_metric = metric; 1383 rtext->rt_lifetime = prep->prep_lifetime; 1384 rtext->rt_nhops = prep->prep_hopcount + 1; 1385 rtext->rt_ext_seq = prep->prep_origseq; /* new proxy seq */ 1386 /* 1387 * XXX: proxy entries have no HWMP priv data, 1388 * nullify them to be sure? 1389 */ 1390 } 1391 /* 1392 * Check for frames queued awaiting path discovery. 1393 * XXX probably can tell exactly and avoid remove call 1394 * NB: hash may have false matches, if so they will get 1395 * stuck back on the stageq because there won't be 1396 * a path. 1397 */ 1398 addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ? 1399 prep->prep_target_ext_addr : prep->prep_targetaddr; 1400 m = ieee80211_ageq_remove(&ic->ic_stageq, 1401 (struct ieee80211_node *)(uintptr_t) 1402 ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */ 1403 for (; m != NULL; m = next) { 1404 next = m->m_nextpkt; 1405 m->m_nextpkt = NULL; 1406 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1407 "flush queued frame %p len %d", m, m->m_pkthdr.len); 1408 ifp->if_transmit(ifp, m); 1409 } 1410#undef IS_PROXY 1411#undef PROXIED_BY_US 1412} 1413 1414static int 1415hwmp_send_prep(struct ieee80211_node *ni, 1416 const uint8_t sa[IEEE80211_ADDR_LEN], 1417 const uint8_t da[IEEE80211_ADDR_LEN], 1418 struct ieee80211_meshprep_ie *prep) 1419{ 1420 /* NB: there's no PREP minimum interval. */ 1421 1422 /* 1423 * mesh prep action frame format 1424 * [6] da 1425 * [6] sa 1426 * [6] addr3 = sa 1427 * [1] action 1428 * [1] category 1429 * [tlv] mesh path reply 1430 */ 1431 prep->prep_ie = IEEE80211_ELEMID_MESHPREP; 1432 prep->prep_len = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ? 1433 IEEE80211_MESHPREP_BASE_SZ_AE : IEEE80211_MESHPREP_BASE_SZ; 1434 return hwmp_send_action(ni, sa, da, (uint8_t *)prep, 1435 prep->prep_len + 2); 1436} 1437 1438#define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags 1439#define PERR_DADDR(n) perr.perr_dests[n].dest_addr 1440#define PERR_DSEQ(n) perr.perr_dests[n].dest_seq 1441#define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode 1442static void 1443hwmp_peerdown(struct ieee80211_node *ni) 1444{ 1445 struct ieee80211vap *vap = ni->ni_vap; 1446 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1447 struct ieee80211_meshperr_ie perr; 1448 struct ieee80211_mesh_route *rt; 1449 struct ieee80211_hwmp_route *hr; 1450 1451 rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr); 1452 if (rt == NULL) 1453 return; 1454 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1455 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1456 "%s", "delete route entry"); 1457 perr.perr_ttl = ms->ms_ttl; 1458 perr.perr_ndests = 1; 1459 PERR_DFLAGS(0) = 0; 1460 if (hr->hr_seq == 0) 1461 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN; 1462 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC; 1463 IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest); 1464 PERR_DSEQ(0) = hr->hr_seq; 1465 PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH; 1466 /* NB: flush everything passing through peer */ 1467 ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr); 1468 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr); 1469} 1470#undef PERR_DFLAGS 1471#undef PERR_DADDR 1472#undef PERR_DSEQ 1473#undef PERR_DRCODE 1474 1475#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags 1476#define PERR_DADDR(n) perr->perr_dests[n].dest_addr 1477#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq 1478#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode 1479static void 1480hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni, 1481 const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr) 1482{ 1483 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1484 struct ieee80211_mesh_route *rt = NULL; 1485 struct ieee80211_hwmp_route *hr; 1486 struct ieee80211_meshperr_ie pperr; 1487 int i, forward = 0; 1488 1489 /* 1490 * Acceptance criteria: check if we received a PERR from a 1491 * neighbor and forwarding is enabled. 1492 */ 1493 if (ni == vap->iv_bss || 1494 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1495 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) 1496 return; 1497 /* 1498 * Find all routing entries that match and delete them. 1499 */ 1500 for (i = 0; i < perr->perr_ndests; i++) { 1501 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i)); 1502 if (rt == NULL) 1503 continue; 1504 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1505 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 1506 HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) { 1507 ieee80211_mesh_rt_del(vap, rt->rt_dest); 1508 ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest); 1509 rt = NULL; 1510 forward = 1; 1511 } 1512 } 1513 /* 1514 * Propagate the PERR if we previously found it on our routing table. 1515 * XXX handle ndest > 1 1516 */ 1517 if (forward && perr->perr_ttl > 1) { 1518 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1519 "propagate PERR from %6D", wh->i_addr2, ":"); 1520 memcpy(&pperr, perr, sizeof(*perr)); 1521 pperr.perr_ttl--; 1522 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, 1523 &pperr); 1524 } 1525} 1526#undef PERR_DFLAGS 1527#undef PEER_DADDR 1528#undef PERR_DSEQ 1529#undef PERR_DRCODE 1530 1531static int 1532hwmp_send_perr(struct ieee80211_node *ni, 1533 const uint8_t sa[IEEE80211_ADDR_LEN], 1534 const uint8_t da[IEEE80211_ADDR_LEN], 1535 struct ieee80211_meshperr_ie *perr) 1536{ 1537 struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; 1538 int i; 1539 uint8_t length = 0; 1540 1541 /* 1542 * Enforce PERR interval. 1543 */ 1544 if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0) 1545 return EALREADY; 1546 getmicrouptime(&hs->hs_lastperr); 1547 1548 /* 1549 * mesh perr action frame format 1550 * [6] da 1551 * [6] sa 1552 * [6] addr3 = sa 1553 * [1] action 1554 * [1] category 1555 * [tlv] mesh path error 1556 */ 1557 perr->perr_ie = IEEE80211_ELEMID_MESHPERR; 1558 length = IEEE80211_MESHPERR_BASE_SZ; 1559 for (i = 0; i<perr->perr_ndests; i++) { 1560 if (perr->perr_dests[i].dest_flags & 1561 IEEE80211_MESHPERR_FLAGS_AE) { 1562 length += IEEE80211_MESHPERR_DEST_SZ_AE; 1563 continue ; 1564 } 1565 length += IEEE80211_MESHPERR_DEST_SZ; 1566 } 1567 perr->perr_len =length; 1568 return hwmp_send_action(ni, sa, da, (uint8_t *)perr, perr->perr_len+2); 1569} 1570 1571static void 1572hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni, 1573 const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann) 1574{ 1575 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1576 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1577 struct ieee80211_mesh_route *rt = NULL; 1578 struct ieee80211_hwmp_route *hr; 1579 struct ieee80211_meshrann_ie prann; 1580 1581 if (ni == vap->iv_bss || 1582 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1583 IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr)) 1584 return; 1585 1586 rt = ieee80211_mesh_rt_find(vap, rann->rann_addr); 1587 /* 1588 * Discover the path to the root mesh STA. 1589 * If we already know it, propagate the RANN element. 1590 */ 1591 if (rt == NULL) { 1592 hwmp_discover(vap, rann->rann_addr, NULL); 1593 return; 1594 } 1595 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1596 if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) { 1597 hr->hr_seq = rann->rann_seq; 1598 if (rann->rann_ttl > 1 && 1599 rann->rann_hopcount < hs->hs_maxhops && 1600 (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 1601 memcpy(&prann, rann, sizeof(prann)); 1602 prann.rann_hopcount += 1; 1603 prann.rann_ttl -= 1; 1604 prann.rann_metric += ms->ms_pmetric->mpm_metric(ni); 1605 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, 1606 broadcastaddr, &prann); 1607 } 1608 } 1609} 1610 1611static int 1612hwmp_send_rann(struct ieee80211_node *ni, 1613 const uint8_t sa[IEEE80211_ADDR_LEN], 1614 const uint8_t da[IEEE80211_ADDR_LEN], 1615 struct ieee80211_meshrann_ie *rann) 1616{ 1617 /* 1618 * mesh rann action frame format 1619 * [6] da 1620 * [6] sa 1621 * [6] addr3 = sa 1622 * [1] action 1623 * [1] category 1624 * [tlv] root annoucement 1625 */ 1626 rann->rann_ie = IEEE80211_ELEMID_MESHRANN; 1627 rann->rann_len = IEEE80211_MESHRANN_BASE_SZ; 1628 return hwmp_send_action(ni, sa, da, (uint8_t *)rann, 1629 rann->rann_len + 2); 1630} 1631 1632#define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 1633#define PREQ_TADDR(n) preq.preq_targets[n].target_addr 1634#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 1635static struct ieee80211_node * 1636hwmp_discover(struct ieee80211vap *vap, 1637 const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m) 1638{ 1639 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1640 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1641 struct ieee80211_mesh_route *rt = NULL; 1642 struct ieee80211_hwmp_route *hr; 1643 struct ieee80211_meshpreq_ie preq; 1644 struct ieee80211_node *ni; 1645 int sendpreq = 0; 1646 1647 KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 1648 ("not a mesh vap, opmode %d", vap->iv_opmode)); 1649 1650 KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest), 1651 ("%s: discovering self!", __func__)); 1652 1653 ni = NULL; 1654 if (!IEEE80211_IS_MULTICAST(dest)) { 1655 rt = ieee80211_mesh_rt_find(vap, dest); 1656 if (rt == NULL) { 1657 rt = ieee80211_mesh_rt_add(vap, dest); 1658 if (rt == NULL) { 1659 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 1660 ni, "unable to add discovery path to %6D", 1661 dest, ":"); 1662 vap->iv_stats.is_mesh_rtaddfailed++; 1663 goto done; 1664 } 1665 } 1666 hr = IEEE80211_MESH_ROUTE_PRIV(rt, 1667 struct ieee80211_hwmp_route); 1668 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { 1669 if (hr->hr_lastdiscovery != 0 && 1670 (ticks - hr->hr_lastdiscovery < 1671 (ieee80211_hwmp_net_diameter_traversaltime * 2))) { 1672 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 1673 dest, NULL, "%s", 1674 "too frequent discovery requeust"); 1675 /* XXX: stats? */ 1676 goto done; 1677 } 1678 hr->hr_lastdiscovery = ticks; 1679 if (hr->hr_preqretries >= 1680 ieee80211_hwmp_maxpreq_retries) { 1681 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 1682 dest, NULL, "%s", 1683 "no valid path , max number of discovery"); 1684 vap->iv_stats.is_mesh_fwd_nopath++; 1685 goto done; 1686 } 1687 hr->hr_preqretries++; 1688 if (hr->hr_origseq == 0) 1689 hr->hr_origseq = ++hs->hs_seq; 1690 rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 1691 /* XXX: special discovery timeout, larger lifetime? */ 1692 ieee80211_mesh_rt_update(rt, 1693 ticks_to_msecs(ieee80211_hwmp_pathtimeout)); 1694 sendpreq = 1; 1695 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, 1696 "start path discovery (src %s), target seq %u", 1697 m == NULL ? "<none>" : ether_sprintf( 1698 mtod(m, struct ether_header *)->ether_shost), 1699 hr->hr_seq); 1700 /* 1701 * Try to discover the path for this node. 1702 * Group addressed PREQ Case A 1703 */ 1704 preq.preq_flags = 0; 1705 preq.preq_hopcount = 0; 1706 preq.preq_ttl = ms->ms_ttl; 1707 preq.preq_id = ++hs->hs_preqid; 1708 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 1709 preq.preq_origseq = hr->hr_origseq; 1710 preq.preq_lifetime = 1711 ticks_to_msecs(ieee80211_hwmp_pathtimeout); 1712 preq.preq_metric = rt->rt_metric; 1713 preq.preq_tcount = 1; 1714 IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest); 1715 PREQ_TFLAGS(0) = 0; 1716 if (ieee80211_hwmp_targetonly) 1717 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO; 1718 if (ieee80211_hwmp_replyforward) 1719 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF; 1720 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN; 1721 PREQ_TSEQ(0) = hr->hr_seq; 1722 /* XXX check return value */ 1723 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, 1724 broadcastaddr, &preq, &hr->hr_lastpreq, 1725 &ieee80211_hwmp_preqminint); 1726 } 1727 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) 1728 ni = ieee80211_find_txnode(vap, rt->rt_nexthop); 1729 } else { 1730 ni = ieee80211_find_txnode(vap, dest); 1731 /* NB: if null then we leak mbuf */ 1732 KASSERT(ni != NULL, ("leak mcast frame")); 1733 return ni; 1734 } 1735done: 1736 if (ni == NULL && m != NULL) { 1737 if (sendpreq) { 1738 struct ieee80211com *ic = vap->iv_ic; 1739 /* 1740 * Queue packet for transmit when path discovery 1741 * completes. If discovery never completes the 1742 * frame will be flushed by way of the aging timer. 1743 */ 1744 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, 1745 "%s", "queue frame until path found"); 1746 m->m_pkthdr.rcvif = (void *)(uintptr_t) 1747 ieee80211_mac_hash(ic, dest); 1748 /* XXX age chosen randomly */ 1749 ieee80211_ageq_append(&ic->ic_stageq, m, 1750 IEEE80211_INACT_WAIT); 1751 } else { 1752 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 1753 dest, NULL, "%s", "no valid path to this node"); 1754 m_freem(m); 1755 } 1756 } 1757 return ni; 1758} 1759#undef PREQ_TFLAGS 1760#undef PREQ_TADDR 1761#undef PREQ_TSEQ 1762 1763static int 1764hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1765{ 1766 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1767 int error; 1768 1769 if (vap->iv_opmode != IEEE80211_M_MBSS) 1770 return ENOSYS; 1771 error = 0; 1772 switch (ireq->i_type) { 1773 case IEEE80211_IOC_HWMP_ROOTMODE: 1774 ireq->i_val = hs->hs_rootmode; 1775 break; 1776 case IEEE80211_IOC_HWMP_MAXHOPS: 1777 ireq->i_val = hs->hs_maxhops; 1778 break; 1779 default: 1780 return ENOSYS; 1781 } 1782 return error; 1783} 1784IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211); 1785 1786static int 1787hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1788{ 1789 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1790 int error; 1791 1792 if (vap->iv_opmode != IEEE80211_M_MBSS) 1793 return ENOSYS; 1794 error = 0; 1795 switch (ireq->i_type) { 1796 case IEEE80211_IOC_HWMP_ROOTMODE: 1797 if (ireq->i_val < 0 || ireq->i_val > 3) 1798 return EINVAL; 1799 hs->hs_rootmode = ireq->i_val; 1800 hwmp_rootmode_setup(vap); 1801 break; 1802 case IEEE80211_IOC_HWMP_MAXHOPS: 1803 if (ireq->i_val <= 0 || ireq->i_val > 255) 1804 return EINVAL; 1805 hs->hs_maxhops = ireq->i_val; 1806 break; 1807 default: 1808 return ENOSYS; 1809 } 1810 return error; 1811} 1812IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211); 1813