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 * $FreeBSD: head/sys/net80211/ieee80211_hwmp.c 198581 2009-10-29 12:19:10Z rpaulo $ 30 */ 31 32 /* 33 * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP. 34 * 35 * Based on March 2009, D3.0 802.11s draft spec. 36 */ 37 #include "opt_inet.h" 38 #include "opt_wlan.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mbuf.h> 43 #include <sys/malloc.h> 44 #include <sys/kernel.h> 45 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/endian.h> 49 #include <sys/errno.h> 50 #include <sys/proc.h> 51 #include <sys/sysctl.h> 52 53 #include <net/if.h> 54 #include <net/if_media.h> 55 #include <net/if_llc.h> 56 #include <net/ethernet.h> 57 #include <net/route.h> 58 59 #include <net/bpf.h> 60 61 #include <netproto/802_11/ieee80211_var.h> 62 #include <netproto/802_11/ieee80211_action.h> 63 #include <netproto/802_11/ieee80211_input.h> 64 #include <netproto/802_11/ieee80211_mesh.h> 65 66 static void hwmp_vattach(struct ieee80211vap *); 67 static void hwmp_vdetach(struct ieee80211vap *); 68 static int hwmp_newstate(struct ieee80211vap *, 69 enum ieee80211_state, int); 70 static int hwmp_send_action(struct ieee80211_node *, 71 const uint8_t [IEEE80211_ADDR_LEN], 72 const uint8_t [IEEE80211_ADDR_LEN], 73 uint8_t *, size_t); 74 static uint8_t * hwmp_add_meshpreq(uint8_t *, 75 const struct ieee80211_meshpreq_ie *); 76 static uint8_t * hwmp_add_meshprep(uint8_t *, 77 const struct ieee80211_meshprep_ie *); 78 static uint8_t * hwmp_add_meshperr(uint8_t *, 79 const struct ieee80211_meshperr_ie *); 80 static uint8_t * hwmp_add_meshrann(uint8_t *, 81 const struct ieee80211_meshrann_ie *); 82 static void hwmp_rootmode_setup(struct ieee80211vap *); 83 static void hwmp_rootmode_callout(void *); 84 static void hwmp_rootmode_rann_callout(void *); 85 static void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *, 86 const struct ieee80211_frame *, 87 const struct ieee80211_meshpreq_ie *); 88 static int hwmp_send_preq(struct ieee80211_node *, 89 const uint8_t [IEEE80211_ADDR_LEN], 90 const uint8_t [IEEE80211_ADDR_LEN], 91 struct ieee80211_meshpreq_ie *); 92 static void hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *, 93 const struct ieee80211_frame *, 94 const struct ieee80211_meshprep_ie *); 95 static int hwmp_send_prep(struct ieee80211_node *, 96 const uint8_t [IEEE80211_ADDR_LEN], 97 const uint8_t [IEEE80211_ADDR_LEN], 98 struct ieee80211_meshprep_ie *); 99 static void hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *, 100 const struct ieee80211_frame *, 101 const struct ieee80211_meshperr_ie *); 102 static int hwmp_send_perr(struct ieee80211_node *, 103 const uint8_t [IEEE80211_ADDR_LEN], 104 const uint8_t [IEEE80211_ADDR_LEN], 105 struct ieee80211_meshperr_ie *); 106 static void hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *, 107 const struct ieee80211_frame *, 108 const struct ieee80211_meshrann_ie *); 109 static int hwmp_send_rann(struct ieee80211_node *, 110 const uint8_t [IEEE80211_ADDR_LEN], 111 const uint8_t [IEEE80211_ADDR_LEN], 112 struct ieee80211_meshrann_ie *); 113 static struct ieee80211_node * 114 hwmp_discover(struct ieee80211vap *, 115 const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *); 116 static void hwmp_peerdown(struct ieee80211_node *); 117 118 static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 }; 119 static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 }; 120 121 /* unalligned little endian access */ 122 #define LE_WRITE_2(p, v) do { \ 123 ((uint8_t *)(p))[0] = (v) & 0xff; \ 124 ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 125 } while (0) 126 #define LE_WRITE_4(p, v) do { \ 127 ((uint8_t *)(p))[0] = (v) & 0xff; \ 128 ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 129 ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 130 ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 131 } while (0) 132 133 134 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */ 135 static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] = 136 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 137 138 typedef uint32_t ieee80211_hwmp_seq; 139 #define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0) 140 #define HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0) 141 #define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0) 142 #define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0) 143 144 /* 145 * Private extension of ieee80211_mesh_route. 146 */ 147 struct ieee80211_hwmp_route { 148 ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/ 149 ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */ 150 ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/ 151 int hr_preqretries; 152 }; 153 struct ieee80211_hwmp_state { 154 ieee80211_hwmp_seq hs_seq; /* next seq to be used */ 155 ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */ 156 struct timeval hs_lastpreq; /* last time we sent a PREQ */ 157 struct timeval hs_lastperr; /* last time we sent a PERR */ 158 int hs_rootmode; /* proactive HWMP */ 159 struct callout hs_roottimer; 160 uint8_t hs_maxhops; /* max hop count */ 161 }; 162 163 SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, 164 "IEEE 802.11s HWMP parameters"); 165 static int ieee80211_hwmp_targetonly = 0; 166 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, 167 &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs"); 168 static int ieee80211_hwmp_replyforward = 1; 169 SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW, 170 &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs"); 171 static int ieee80211_hwmp_pathtimeout = -1; 172 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW, 173 &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 174 "path entry lifetime (ms)"); 175 static int ieee80211_hwmp_roottimeout = -1; 176 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW, 177 &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 178 "root PREQ timeout (ms)"); 179 static int ieee80211_hwmp_rootint = -1; 180 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW, 181 &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I", 182 "root interval (ms)"); 183 static int ieee80211_hwmp_rannint = -1; 184 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW, 185 &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I", 186 "root announcement interval (ms)"); 187 188 #define IEEE80211_HWMP_DEFAULT_MAXHOPS 31 189 190 static ieee80211_recv_action_func hwmp_recv_action_meshpath; 191 192 static struct ieee80211_mesh_proto_path mesh_proto_hwmp = { 193 .mpp_descr = "HWMP", 194 .mpp_ie = IEEE80211_MESHCONF_PATH_HWMP, 195 .mpp_discover = hwmp_discover, 196 .mpp_peerdown = hwmp_peerdown, 197 .mpp_vattach = hwmp_vattach, 198 .mpp_vdetach = hwmp_vdetach, 199 .mpp_newstate = hwmp_newstate, 200 .mpp_privlen = sizeof(struct ieee80211_hwmp_route), 201 }; 202 SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW, 203 &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I", 204 "mesh route inactivity timeout (ms)"); 205 206 207 static void 208 ieee80211_hwmp_init(void) 209 { 210 ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000); 211 ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000); 212 ieee80211_hwmp_rootint = msecs_to_ticks(2*1000); 213 ieee80211_hwmp_rannint = msecs_to_ticks(1*1000); 214 215 /* 216 * Register action frame handler. 217 */ 218 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH, 219 IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath); 220 221 /* NB: default is 5 secs per spec */ 222 mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000); 223 224 /* 225 * Register HWMP. 226 */ 227 ieee80211_mesh_register_proto_path(&mesh_proto_hwmp); 228 } 229 SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL); 230 231 void 232 hwmp_vattach(struct ieee80211vap *vap) 233 { 234 struct ieee80211_hwmp_state *hs; 235 236 KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 237 ("not a mesh vap, opmode %d", vap->iv_opmode)); 238 239 hs = kmalloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP, 240 M_INTWAIT | M_ZERO); 241 if (hs == NULL) { 242 kprintf("%s: couldn't alloc HWMP state\n", __func__); 243 return; 244 } 245 hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS; 246 callout_init_mp(&hs->hs_roottimer); 247 vap->iv_hwmp = hs; 248 } 249 250 void 251 hwmp_vdetach(struct ieee80211vap *vap) 252 { 253 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 254 255 callout_stop(&hs->hs_roottimer); 256 kfree(vap->iv_hwmp, M_80211_VAP); 257 vap->iv_hwmp = NULL; 258 } 259 260 int 261 hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg) 262 { 263 enum ieee80211_state nstate = vap->iv_state; 264 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 265 266 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", 267 __func__, ieee80211_state_name[ostate], 268 ieee80211_state_name[nstate], arg); 269 270 if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) 271 callout_stop(&hs->hs_roottimer); 272 if (nstate == IEEE80211_S_RUN) 273 hwmp_rootmode_setup(vap); 274 return 0; 275 } 276 277 static int 278 hwmp_recv_action_meshpath(struct ieee80211_node *ni, 279 const struct ieee80211_frame *wh, 280 const uint8_t *frm, const uint8_t *efrm) 281 { 282 struct ieee80211vap *vap = ni->ni_vap; 283 struct ieee80211_meshpreq_ie preq; 284 struct ieee80211_meshprep_ie prep; 285 struct ieee80211_meshperr_ie perr; 286 struct ieee80211_meshrann_ie rann; 287 const uint8_t *iefrm = frm + 2; /* action + code */ 288 int found = 0; 289 290 while (efrm - iefrm > 1) { 291 IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0); 292 switch (*iefrm) { 293 case IEEE80211_ELEMID_MESHPREQ: 294 { 295 const struct ieee80211_meshpreq_ie *mpreq = 296 (const struct ieee80211_meshpreq_ie *) iefrm; 297 /* XXX > 1 target */ 298 if (mpreq->preq_len != 299 sizeof(struct ieee80211_meshpreq_ie) - 2) { 300 IEEE80211_DISCARD(vap, 301 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 302 wh, NULL, "%s", "PREQ with wrong len"); 303 vap->iv_stats.is_rx_mgtdiscard++; 304 break; 305 } 306 memcpy(&preq, mpreq, sizeof(preq)); 307 preq.preq_id = LE_READ_4(&mpreq->preq_id); 308 preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq); 309 preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime); 310 preq.preq_metric = LE_READ_4(&mpreq->preq_metric); 311 preq.preq_targets[0].target_seq = 312 LE_READ_4(&mpreq->preq_targets[0].target_seq); 313 hwmp_recv_preq(vap, ni, wh, &preq); 314 found++; 315 break; 316 } 317 case IEEE80211_ELEMID_MESHPREP: 318 { 319 const struct ieee80211_meshprep_ie *mprep = 320 (const struct ieee80211_meshprep_ie *) iefrm; 321 if (mprep->prep_len != 322 sizeof(struct ieee80211_meshprep_ie) - 2) { 323 IEEE80211_DISCARD(vap, 324 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 325 wh, NULL, "%s", "PREP with wrong len"); 326 vap->iv_stats.is_rx_mgtdiscard++; 327 break; 328 } 329 memcpy(&prep, mprep, sizeof(prep)); 330 prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq); 331 prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime); 332 prep.prep_metric = LE_READ_4(&mprep->prep_metric); 333 prep.prep_origseq = LE_READ_4(&mprep->prep_origseq); 334 hwmp_recv_prep(vap, ni, wh, &prep); 335 found++; 336 break; 337 } 338 case IEEE80211_ELEMID_MESHPERR: 339 { 340 const struct ieee80211_meshperr_ie *mperr = 341 (const struct ieee80211_meshperr_ie *) iefrm; 342 /* XXX > 1 target */ 343 if (mperr->perr_len != 344 sizeof(struct ieee80211_meshperr_ie) - 2) { 345 IEEE80211_DISCARD(vap, 346 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 347 wh, NULL, "%s", "PERR with wrong len"); 348 vap->iv_stats.is_rx_mgtdiscard++; 349 break; 350 } 351 memcpy(&perr, mperr, sizeof(perr)); 352 perr.perr_dests[0].dest_seq = 353 LE_READ_4(&mperr->perr_dests[0].dest_seq); 354 hwmp_recv_perr(vap, ni, wh, &perr); 355 found++; 356 break; 357 } 358 case IEEE80211_ELEMID_MESHRANN: 359 { 360 const struct ieee80211_meshrann_ie *mrann = 361 (const struct ieee80211_meshrann_ie *) iefrm; 362 if (mrann->rann_len != 363 sizeof(struct ieee80211_meshrann_ie) - 2) { 364 IEEE80211_DISCARD(vap, 365 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 366 wh, NULL, "%s", "RAN with wrong len"); 367 vap->iv_stats.is_rx_mgtdiscard++; 368 return 1; 369 } 370 memcpy(&rann, mrann, sizeof(rann)); 371 rann.rann_seq = LE_READ_4(&mrann->rann_seq); 372 rann.rann_metric = LE_READ_4(&mrann->rann_metric); 373 hwmp_recv_rann(vap, ni, wh, &rann); 374 found++; 375 break; 376 } 377 } 378 iefrm += iefrm[1] + 2; 379 } 380 if (!found) { 381 IEEE80211_DISCARD(vap, 382 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 383 wh, NULL, "%s", "PATH SEL action without IE"); 384 vap->iv_stats.is_rx_mgtdiscard++; 385 } 386 return 0; 387 } 388 389 static int 390 hwmp_send_action(struct ieee80211_node *ni, 391 const uint8_t sa[IEEE80211_ADDR_LEN], 392 const uint8_t da[IEEE80211_ADDR_LEN], 393 uint8_t *ie, size_t len) 394 { 395 struct ieee80211vap *vap = ni->ni_vap; 396 struct ieee80211com *ic = ni->ni_ic; 397 struct ieee80211_bpf_params params; 398 struct mbuf *m; 399 uint8_t *frm; 400 401 if (vap->iv_state == IEEE80211_S_CAC) { 402 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 403 "block %s frame in CAC state", "HWMP action"); 404 vap->iv_stats.is_tx_badstate++; 405 return EIO; /* XXX */ 406 } 407 408 KASSERT(ni != NULL, ("null node")); 409 /* 410 * Hold a reference on the node so it doesn't go away until after 411 * the xmit is complete all the way in the driver. On error we 412 * will remove our reference. 413 */ 414 #ifdef IEEE80211_DEBUG_REFCNT 415 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 416 "ieee80211_ref_node (%s:%u) %p<%6D> refcnt %d\n", 417 __func__, __LINE__, 418 ni, ni->ni_macaddr, ":", 419 ieee80211_node_refcnt(ni)+1); 420 #endif 421 ieee80211_ref_node(ni); 422 423 m = ieee80211_getmgtframe(&frm, 424 ic->ic_headroom + sizeof(struct ieee80211_frame), 425 sizeof(struct ieee80211_action) + len 426 ); 427 if (m == NULL) { 428 ieee80211_free_node(ni); 429 vap->iv_stats.is_tx_nobuf++; 430 return ENOMEM; 431 } 432 *frm++ = IEEE80211_ACTION_CAT_MESHPATH; 433 *frm++ = IEEE80211_ACTION_MESHPATH_SEL; 434 switch (*ie) { 435 case IEEE80211_ELEMID_MESHPREQ: 436 frm = hwmp_add_meshpreq(frm, 437 (struct ieee80211_meshpreq_ie *)ie); 438 break; 439 case IEEE80211_ELEMID_MESHPREP: 440 frm = hwmp_add_meshprep(frm, 441 (struct ieee80211_meshprep_ie *)ie); 442 break; 443 case IEEE80211_ELEMID_MESHPERR: 444 frm = hwmp_add_meshperr(frm, 445 (struct ieee80211_meshperr_ie *)ie); 446 break; 447 case IEEE80211_ELEMID_MESHRANN: 448 frm = hwmp_add_meshrann(frm, 449 (struct ieee80211_meshrann_ie *)ie); 450 break; 451 } 452 453 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 454 M_PREPEND(m, sizeof(struct ieee80211_frame), MB_DONTWAIT); 455 if (m == NULL) { 456 ieee80211_free_node(ni); 457 vap->iv_stats.is_tx_nobuf++; 458 return ENOMEM; 459 } 460 ieee80211_send_setup(ni, m, 461 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION, 462 IEEE80211_NONQOS_TID, sa, da, sa); 463 464 m->m_flags |= M_ENCAP; /* mark encapsulated */ 465 IEEE80211_NODE_STAT(ni, tx_mgmt); 466 467 memset(¶ms, 0, sizeof(params)); 468 params.ibp_pri = WME_AC_VO; 469 params.ibp_rate0 = ni->ni_txparms->mgmtrate; 470 if (IEEE80211_IS_MULTICAST(da)) 471 params.ibp_try0 = 1; 472 else 473 params.ibp_try0 = ni->ni_txparms->maxretry; 474 params.ibp_power = ni->ni_txpower; 475 return ic->ic_raw_xmit(ni, m, ¶ms); 476 } 477 478 #define ADDSHORT(frm, v) do { \ 479 frm[0] = (v) & 0xff; \ 480 frm[1] = (v) >> 8; \ 481 frm += 2; \ 482 } while (0) 483 #define ADDWORD(frm, v) do { \ 484 LE_WRITE_4(frm, v); \ 485 frm += 4; \ 486 } while (0) 487 /* 488 * Add a Mesh Path Request IE to a frame. 489 */ 490 static uint8_t * 491 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq) 492 { 493 int i; 494 495 *frm++ = IEEE80211_ELEMID_MESHPREQ; 496 *frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 + 497 (preq->preq_tcount - 1) * sizeof(*preq->preq_targets); 498 *frm++ = preq->preq_flags; 499 *frm++ = preq->preq_hopcount; 500 *frm++ = preq->preq_ttl; 501 ADDWORD(frm, preq->preq_id); 502 IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6; 503 ADDWORD(frm, preq->preq_origseq); 504 ADDWORD(frm, preq->preq_lifetime); 505 ADDWORD(frm, preq->preq_metric); 506 *frm++ = preq->preq_tcount; 507 for (i = 0; i < preq->preq_tcount; i++) { 508 *frm++ = preq->preq_targets[i].target_flags; 509 IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr); 510 frm += 6; 511 ADDWORD(frm, preq->preq_targets[i].target_seq); 512 } 513 return frm; 514 } 515 516 /* 517 * Add a Mesh Path Reply IE to a frame. 518 */ 519 static uint8_t * 520 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep) 521 { 522 *frm++ = IEEE80211_ELEMID_MESHPREP; 523 *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2; 524 *frm++ = prep->prep_flags; 525 *frm++ = prep->prep_hopcount; 526 *frm++ = prep->prep_ttl; 527 IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6; 528 ADDWORD(frm, prep->prep_targetseq); 529 ADDWORD(frm, prep->prep_lifetime); 530 ADDWORD(frm, prep->prep_metric); 531 IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6; 532 ADDWORD(frm, prep->prep_origseq); 533 return frm; 534 } 535 536 /* 537 * Add a Mesh Path Error IE to a frame. 538 */ 539 static uint8_t * 540 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr) 541 { 542 int i; 543 544 *frm++ = IEEE80211_ELEMID_MESHPERR; 545 *frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 + 546 (perr->perr_ndests - 1) * sizeof(*perr->perr_dests); 547 *frm++ = perr->perr_ttl; 548 *frm++ = perr->perr_ndests; 549 for (i = 0; i < perr->perr_ndests; i++) { 550 *frm++ = perr->perr_dests[i].dest_flags; 551 IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr); 552 frm += 6; 553 ADDWORD(frm, perr->perr_dests[i].dest_seq); 554 ADDSHORT(frm, perr->perr_dests[i].dest_rcode); 555 } 556 return frm; 557 } 558 559 /* 560 * Add a Root Annoucement IE to a frame. 561 */ 562 static uint8_t * 563 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann) 564 { 565 *frm++ = IEEE80211_ELEMID_MESHRANN; 566 *frm++ = sizeof(struct ieee80211_meshrann_ie) - 2; 567 *frm++ = rann->rann_flags; 568 *frm++ = rann->rann_hopcount; 569 *frm++ = rann->rann_ttl; 570 IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6; 571 ADDWORD(frm, rann->rann_seq); 572 ADDWORD(frm, rann->rann_metric); 573 return frm; 574 } 575 576 static void 577 hwmp_rootmode_setup(struct ieee80211vap *vap) 578 { 579 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 580 581 switch (hs->hs_rootmode) { 582 case IEEE80211_HWMP_ROOTMODE_DISABLED: 583 callout_stop(&hs->hs_roottimer); 584 break; 585 case IEEE80211_HWMP_ROOTMODE_NORMAL: 586 case IEEE80211_HWMP_ROOTMODE_PROACTIVE: 587 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint, 588 hwmp_rootmode_callout, vap); 589 break; 590 case IEEE80211_HWMP_ROOTMODE_RANN: 591 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint, 592 hwmp_rootmode_rann_callout, vap); 593 break; 594 } 595 } 596 597 /* 598 * Send a broadcast Path Request to find all nodes on the mesh. We are 599 * called when the vap is configured as a HWMP root node. 600 */ 601 #define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 602 #define PREQ_TADDR(n) preq.preq_targets[n].target_addr 603 #define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 604 static void 605 hwmp_rootmode_callout(void *arg) 606 { 607 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 608 struct ieee80211_hwmp_state *hs; 609 struct ieee80211_mesh_state *ms; 610 struct ieee80211_meshpreq_ie preq; 611 612 wlan_serialize_enter(); 613 hs = vap->iv_hwmp; 614 ms = vap->iv_mesh; 615 616 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 617 "%s", "send broadcast PREQ"); 618 619 preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; 620 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 621 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR; 622 if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE) 623 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP; 624 preq.preq_hopcount = 0; 625 preq.preq_ttl = ms->ms_ttl; 626 preq.preq_id = ++hs->hs_preqid; 627 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 628 preq.preq_origseq = ++hs->hs_seq; 629 preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout); 630 preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 631 preq.preq_tcount = 1; 632 IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr); 633 PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO | 634 IEEE80211_MESHPREQ_TFLAGS_RF; 635 PREQ_TSEQ(0) = 0; 636 vap->iv_stats.is_hwmp_rootreqs++; 637 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq); 638 hwmp_rootmode_setup(vap); 639 wlan_serialize_exit(); 640 } 641 #undef PREQ_TFLAGS 642 #undef PREQ_TADDR 643 #undef PREQ_TSEQ 644 645 /* 646 * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are 647 * called when the vap is configured as a HWMP RANN root node. 648 */ 649 static void 650 hwmp_rootmode_rann_callout(void *arg) 651 { 652 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 653 struct ieee80211_hwmp_state *hs; 654 struct ieee80211_mesh_state *ms; 655 struct ieee80211_meshrann_ie rann; 656 657 wlan_serialize_enter(); 658 hs = vap->iv_hwmp; 659 ms = vap->iv_mesh; 660 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 661 "%s", "send broadcast RANN"); 662 663 rann.rann_flags = 0; 664 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 665 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR; 666 rann.rann_hopcount = 0; 667 rann.rann_ttl = ms->ms_ttl; 668 IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr); 669 rann.rann_seq = ++hs->hs_seq; 670 rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 671 672 vap->iv_stats.is_hwmp_rootrann++; 673 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann); 674 hwmp_rootmode_setup(vap); 675 wlan_serialize_exit(); 676 } 677 678 #define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags 679 #define PREQ_TADDR(n) preq->preq_targets[n].target_addr 680 #define PREQ_TSEQ(n) preq->preq_targets[n].target_seq 681 static void 682 hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, 683 const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq) 684 { 685 struct ieee80211_mesh_state *ms = vap->iv_mesh; 686 struct ieee80211_mesh_route *rt = NULL; 687 struct ieee80211_mesh_route *rtorig = NULL; 688 struct ieee80211_hwmp_route *hrorig; 689 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 690 struct ieee80211_meshprep_ie prep; 691 692 if (ni == vap->iv_bss || 693 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 694 return; 695 /* 696 * Ignore PREQs from us. Could happen because someone forward it 697 * back to us. 698 */ 699 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr)) 700 return; 701 702 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 703 "received PREQ, source %6D", preq->preq_origaddr, ":"); 704 705 /* 706 * Acceptance criteria: if the PREQ is not for us and 707 * forwarding is disabled, discard this PREQ. 708 */ 709 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) && 710 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 711 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 712 preq->preq_origaddr, NULL, "%s", "not accepting PREQ"); 713 return; 714 } 715 rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); 716 if (rtorig == NULL) 717 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr); 718 if (rtorig == NULL) { 719 /* XXX stat */ 720 return; 721 } 722 hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route); 723 /* 724 * Sequence number validation. 725 */ 726 if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) && 727 HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) { 728 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 729 "discard PREQ from %6D, old seq no %u <= %u", 730 preq->preq_origaddr, ":", 731 preq->preq_origseq, hrorig->hr_seq); 732 return; 733 } 734 hrorig->hr_preqid = preq->preq_id; 735 hrorig->hr_seq = preq->preq_origseq; 736 737 /* 738 * Check if the PREQ is addressed to us. 739 */ 740 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { 741 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 742 "reply to %6D", preq->preq_origaddr, ":"); 743 /* 744 * Build and send a PREP frame. 745 */ 746 prep.prep_flags = 0; 747 prep.prep_hopcount = 0; 748 prep.prep_ttl = ms->ms_ttl; 749 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr); 750 prep.prep_targetseq = ++hs->hs_seq; 751 prep.prep_lifetime = preq->preq_lifetime; 752 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 753 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr); 754 prep.prep_origseq = preq->preq_origseq; 755 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep); 756 /* 757 * Build the reverse path, if we don't have it already. 758 */ 759 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); 760 if (rt == NULL) 761 hwmp_discover(vap, preq->preq_origaddr, NULL); 762 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) 763 hwmp_discover(vap, rt->rt_dest, NULL); 764 return; 765 } 766 /* 767 * Proactive PREQ: reply with a proactive PREP to the 768 * root STA if requested. 769 */ 770 if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) && 771 (PREQ_TFLAGS(0) & 772 ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) == 773 (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) { 774 uint8_t rootmac[IEEE80211_ADDR_LEN]; 775 776 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr); 777 rt = ieee80211_mesh_rt_find(vap, rootmac); 778 if (rt == NULL) { 779 rt = ieee80211_mesh_rt_add(vap, rootmac); 780 if (rt == NULL) { 781 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 782 "unable to add root mesh path to %6D", 783 rootmac, ":"); 784 vap->iv_stats.is_mesh_rtaddfailed++; 785 return; 786 } 787 } 788 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 789 "root mesh station @ %6D", rootmac, ":"); 790 791 /* 792 * Reply with a PREP if we don't have a path to the root 793 * or if the root sent us a proactive PREQ. 794 */ 795 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || 796 (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) { 797 prep.prep_flags = 0; 798 prep.prep_hopcount = 0; 799 prep.prep_ttl = ms->ms_ttl; 800 IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac); 801 prep.prep_origseq = preq->preq_origseq; 802 prep.prep_lifetime = preq->preq_lifetime; 803 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 804 IEEE80211_ADDR_COPY(prep.prep_targetaddr, 805 vap->iv_myaddr); 806 prep.prep_targetseq = ++hs->hs_seq; 807 hwmp_send_prep(vap->iv_bss, vap->iv_myaddr, 808 broadcastaddr, &prep); 809 } 810 hwmp_discover(vap, rootmac, NULL); 811 return; 812 } 813 rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); 814 815 /* 816 * Forwarding and Intermediate reply for PREQs with 1 target. 817 */ 818 if (preq->preq_tcount == 1) { 819 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */ 820 821 memcpy(&ppreq, preq, sizeof(ppreq)); 822 /* 823 * We have a valid route to this node. 824 */ 825 if (rt != NULL && 826 (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { 827 if (preq->preq_ttl > 1 && 828 preq->preq_hopcount < hs->hs_maxhops) { 829 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 830 "forward PREQ from %6D", 831 preq->preq_origaddr, ":"); 832 /* 833 * Propagate the original PREQ. 834 */ 835 ppreq.preq_hopcount += 1; 836 ppreq.preq_ttl -= 1; 837 ppreq.preq_metric += 838 ms->ms_pmetric->mpm_metric(ni); 839 /* 840 * Set TO and unset RF bits because we are going 841 * to send a PREP next. 842 */ 843 ppreq.preq_targets[0].target_flags |= 844 IEEE80211_MESHPREQ_TFLAGS_TO; 845 ppreq.preq_targets[0].target_flags &= 846 ~IEEE80211_MESHPREQ_TFLAGS_RF; 847 hwmp_send_preq(ni, vap->iv_myaddr, 848 broadcastaddr, &ppreq); 849 } 850 /* 851 * Check if we can send an intermediate Path Reply, 852 * i.e., Target Only bit is not set. 853 */ 854 if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) { 855 struct ieee80211_meshprep_ie prep; 856 857 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 858 "intermediate reply for PREQ from %6D", 859 preq->preq_origaddr, ":"); 860 prep.prep_flags = 0; 861 prep.prep_hopcount = rt->rt_nhops + 1; 862 prep.prep_ttl = ms->ms_ttl; 863 IEEE80211_ADDR_COPY(&prep.prep_targetaddr, 864 PREQ_TADDR(0)); 865 prep.prep_targetseq = hrorig->hr_seq; 866 prep.prep_lifetime = preq->preq_lifetime; 867 prep.prep_metric = rt->rt_metric + 868 ms->ms_pmetric->mpm_metric(ni); 869 IEEE80211_ADDR_COPY(&prep.prep_origaddr, 870 preq->preq_origaddr); 871 prep.prep_origseq = hrorig->hr_seq; 872 hwmp_send_prep(ni, vap->iv_myaddr, 873 broadcastaddr, &prep); 874 } 875 /* 876 * We have no information about this path, 877 * propagate the PREQ. 878 */ 879 } else if (preq->preq_ttl > 1 && 880 preq->preq_hopcount < hs->hs_maxhops) { 881 if (rt == NULL) { 882 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0)); 883 if (rt == NULL) { 884 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 885 ni, "unable to add PREQ path to %6D", 886 PREQ_TADDR(0), ":"); 887 vap->iv_stats.is_mesh_rtaddfailed++; 888 return; 889 } 890 } 891 rt->rt_metric = preq->preq_metric; 892 rt->rt_lifetime = preq->preq_lifetime; 893 hrorig = IEEE80211_MESH_ROUTE_PRIV(rt, 894 struct ieee80211_hwmp_route); 895 hrorig->hr_seq = preq->preq_origseq; 896 hrorig->hr_preqid = preq->preq_id; 897 898 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 899 "forward PREQ from %6D", 900 preq->preq_origaddr, ":"); 901 ppreq.preq_hopcount += 1; 902 ppreq.preq_ttl -= 1; 903 ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); 904 hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr, 905 &ppreq); 906 } 907 } 908 909 } 910 #undef PREQ_TFLAGS 911 #undef PREQ_TADDR 912 #undef PREQ_TSEQ 913 914 static int 915 hwmp_send_preq(struct ieee80211_node *ni, 916 const uint8_t sa[IEEE80211_ADDR_LEN], 917 const uint8_t da[IEEE80211_ADDR_LEN], 918 struct ieee80211_meshpreq_ie *preq) 919 { 920 struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; 921 922 /* 923 * Enforce PREQ interval. 924 */ 925 if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0) 926 return EALREADY; 927 getmicrouptime(&hs->hs_lastpreq); 928 929 /* 930 * mesh preq action frame format 931 * [6] da 932 * [6] sa 933 * [6] addr3 = sa 934 * [1] action 935 * [1] category 936 * [tlv] mesh path request 937 */ 938 preq->preq_ie = IEEE80211_ELEMID_MESHPREQ; 939 return hwmp_send_action(ni, sa, da, (uint8_t *)preq, 940 sizeof(struct ieee80211_meshpreq_ie)); 941 } 942 943 static void 944 hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, 945 const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep) 946 { 947 struct ieee80211_mesh_state *ms = vap->iv_mesh; 948 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 949 struct ieee80211_mesh_route *rt = NULL; 950 struct ieee80211_hwmp_route *hr; 951 struct ieee80211com *ic = vap->iv_ic; 952 struct ifnet *ifp = vap->iv_ifp; 953 struct mbuf *m, *next; 954 955 /* 956 * Acceptance criteria: if the corresponding PREQ was not generated 957 * by us and forwarding is disabled, discard this PREP. 958 */ 959 if (ni == vap->iv_bss || 960 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 961 return; 962 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && 963 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) 964 return; 965 966 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 967 "received PREP from %6D", prep->prep_targetaddr, ":"); 968 969 rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr); 970 if (rt == NULL) { 971 /* 972 * If we have no entry this could be a reply to a root PREQ. 973 */ 974 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) { 975 rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr); 976 if (rt == NULL) { 977 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 978 ni, "unable to add PREP path to %6D", 979 prep->prep_targetaddr, ":"); 980 vap->iv_stats.is_mesh_rtaddfailed++; 981 return; 982 } 983 IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); 984 rt->rt_nhops = prep->prep_hopcount; 985 rt->rt_lifetime = prep->prep_lifetime; 986 rt->rt_metric = prep->prep_metric; 987 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 988 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 989 "add root path to %6D nhops %d metric %d (PREP)", 990 prep->prep_targetaddr, ":", 991 rt->rt_nhops, rt->rt_metric); 992 return; 993 } 994 return; 995 } 996 /* 997 * Sequence number validation. 998 */ 999 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1000 if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) { 1001 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1002 "discard PREP from %6D, old seq no %u <= %u", 1003 prep->prep_targetaddr, ":", 1004 prep->prep_targetseq, hr->hr_seq); 1005 return; 1006 } 1007 hr->hr_seq = prep->prep_targetseq; 1008 /* 1009 * If it's NOT for us, propagate the PREP. 1010 */ 1011 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && 1012 prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) { 1013 struct ieee80211_meshprep_ie pprep; /* propagated PREP */ 1014 1015 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1016 "propagate PREP from %6D", 1017 prep->prep_targetaddr, ":"); 1018 1019 memcpy(&pprep, prep, sizeof(pprep)); 1020 pprep.prep_hopcount += 1; 1021 pprep.prep_ttl -= 1; 1022 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni); 1023 IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr); 1024 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep); 1025 } 1026 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1027 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 1028 /* NB: never clobber a proxy entry */; 1029 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1030 "discard PREP for %6D, route is marked PROXY", 1031 prep->prep_targetaddr, ":"); 1032 vap->iv_stats.is_hwmp_proxy++; 1033 } else if (prep->prep_origseq == hr->hr_origseq) { 1034 /* 1035 * Check if we already have a path to this node. 1036 * If we do, check if this path reply contains a 1037 * better route. 1038 */ 1039 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || 1040 (prep->prep_hopcount < rt->rt_nhops || 1041 prep->prep_metric < rt->rt_metric)) { 1042 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1043 "%s path to %6D, hopcount %d:%d metric %d:%d", 1044 rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ? 1045 "prefer" : "update", 1046 prep->prep_origaddr, ":", 1047 rt->rt_nhops, prep->prep_hopcount, 1048 rt->rt_metric, prep->prep_metric); 1049 IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); 1050 rt->rt_nhops = prep->prep_hopcount; 1051 rt->rt_lifetime = prep->prep_lifetime; 1052 rt->rt_metric = prep->prep_metric; 1053 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 1054 } else { 1055 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1056 "ignore PREP for %6D, hopcount %d:%d metric %d:%d", 1057 prep->prep_targetaddr, ":", 1058 rt->rt_nhops, prep->prep_hopcount, 1059 rt->rt_metric, prep->prep_metric); 1060 } 1061 } else { 1062 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1063 "discard PREP for %6D, wrong seqno %u != %u", 1064 prep->prep_targetaddr, ":", prep->prep_origseq, 1065 hr->hr_seq); 1066 vap->iv_stats.is_hwmp_wrongseq++; 1067 } 1068 /* 1069 * Check for frames queued awaiting path discovery. 1070 * XXX probably can tell exactly and avoid remove call 1071 * NB: hash may have false matches, if so they will get 1072 * stuck back on the stageq because there won't be 1073 * a path. 1074 */ 1075 m = ieee80211_ageq_remove(&ic->ic_stageq, 1076 (struct ieee80211_node *)(uintptr_t) 1077 ieee80211_mac_hash(ic, rt->rt_dest)); 1078 for (; m != NULL; m = next) { 1079 next = m->m_nextpkt; 1080 m->m_nextpkt = NULL; 1081 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1082 "flush queued frame %p len %d", m, m->m_pkthdr.len); 1083 ieee80211_handoff(ifp, m); 1084 } 1085 } 1086 1087 static int 1088 hwmp_send_prep(struct ieee80211_node *ni, 1089 const uint8_t sa[IEEE80211_ADDR_LEN], 1090 const uint8_t da[IEEE80211_ADDR_LEN], 1091 struct ieee80211_meshprep_ie *prep) 1092 { 1093 /* NB: there's no PREP minimum interval. */ 1094 1095 /* 1096 * mesh prep action frame format 1097 * [6] da 1098 * [6] sa 1099 * [6] addr3 = sa 1100 * [1] action 1101 * [1] category 1102 * [tlv] mesh path reply 1103 */ 1104 prep->prep_ie = IEEE80211_ELEMID_MESHPREP; 1105 return hwmp_send_action(ni, sa, da, (uint8_t *)prep, 1106 sizeof(struct ieee80211_meshprep_ie)); 1107 } 1108 1109 #define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags 1110 #define PERR_DADDR(n) perr.perr_dests[n].dest_addr 1111 #define PERR_DSEQ(n) perr.perr_dests[n].dest_seq 1112 #define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode 1113 static void 1114 hwmp_peerdown(struct ieee80211_node *ni) 1115 { 1116 struct ieee80211vap *vap = ni->ni_vap; 1117 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1118 struct ieee80211_meshperr_ie perr; 1119 struct ieee80211_mesh_route *rt; 1120 struct ieee80211_hwmp_route *hr; 1121 1122 rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr); 1123 if (rt == NULL) 1124 return; 1125 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1126 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1127 "%s", "delete route entry"); 1128 perr.perr_ttl = ms->ms_ttl; 1129 perr.perr_ndests = 1; 1130 PERR_DFLAGS(0) = 0; 1131 if (hr->hr_seq == 0) 1132 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN; 1133 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC; 1134 IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest); 1135 PERR_DSEQ(0) = hr->hr_seq; 1136 PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH; 1137 /* NB: flush everything passing through peer */ 1138 ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr); 1139 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr); 1140 } 1141 #undef PERR_DFLAGS 1142 #undef PERR_DADDR 1143 #undef PERR_DSEQ 1144 #undef PERR_DRCODE 1145 1146 #define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags 1147 #define PERR_DADDR(n) perr->perr_dests[n].dest_addr 1148 #define PERR_DSEQ(n) perr->perr_dests[n].dest_seq 1149 #define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode 1150 static void 1151 hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni, 1152 const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr) 1153 { 1154 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1155 struct ieee80211_mesh_route *rt = NULL; 1156 struct ieee80211_hwmp_route *hr; 1157 struct ieee80211_meshperr_ie pperr; 1158 int i, forward = 0; 1159 1160 /* 1161 * Acceptance criteria: check if we received a PERR from a 1162 * neighbor and forwarding is enabled. 1163 */ 1164 if (ni == vap->iv_bss || 1165 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1166 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) 1167 return; 1168 /* 1169 * Find all routing entries that match and delete them. 1170 */ 1171 for (i = 0; i < perr->perr_ndests; i++) { 1172 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i)); 1173 if (rt == NULL) 1174 continue; 1175 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1176 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 1177 HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) { 1178 ieee80211_mesh_rt_del(vap, rt->rt_dest); 1179 ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest); 1180 rt = NULL; 1181 forward = 1; 1182 } 1183 } 1184 /* 1185 * Propagate the PERR if we previously found it on our routing table. 1186 * XXX handle ndest > 1 1187 */ 1188 if (forward && perr->perr_ttl > 1) { 1189 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1190 "propagate PERR from %6D", wh->i_addr2, ":"); 1191 memcpy(&pperr, perr, sizeof(*perr)); 1192 pperr.perr_ttl--; 1193 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, 1194 &pperr); 1195 } 1196 } 1197 #undef PEER_DADDR 1198 #undef PERR_DSEQ 1199 1200 static int 1201 hwmp_send_perr(struct ieee80211_node *ni, 1202 const uint8_t sa[IEEE80211_ADDR_LEN], 1203 const uint8_t da[IEEE80211_ADDR_LEN], 1204 struct ieee80211_meshperr_ie *perr) 1205 { 1206 struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; 1207 1208 /* 1209 * Enforce PERR interval. 1210 */ 1211 if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0) 1212 return EALREADY; 1213 getmicrouptime(&hs->hs_lastperr); 1214 1215 /* 1216 * mesh perr action frame format 1217 * [6] da 1218 * [6] sa 1219 * [6] addr3 = sa 1220 * [1] action 1221 * [1] category 1222 * [tlv] mesh path error 1223 */ 1224 perr->perr_ie = IEEE80211_ELEMID_MESHPERR; 1225 return hwmp_send_action(ni, sa, da, (uint8_t *)perr, 1226 sizeof(struct ieee80211_meshperr_ie)); 1227 } 1228 1229 static void 1230 hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni, 1231 const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann) 1232 { 1233 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1234 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1235 struct ieee80211_mesh_route *rt = NULL; 1236 struct ieee80211_hwmp_route *hr; 1237 struct ieee80211_meshrann_ie prann; 1238 1239 if (ni == vap->iv_bss || 1240 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1241 IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr)) 1242 return; 1243 1244 rt = ieee80211_mesh_rt_find(vap, rann->rann_addr); 1245 /* 1246 * Discover the path to the root mesh STA. 1247 * If we already know it, propagate the RANN element. 1248 */ 1249 if (rt == NULL) { 1250 hwmp_discover(vap, rann->rann_addr, NULL); 1251 return; 1252 } 1253 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1254 if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) { 1255 hr->hr_seq = rann->rann_seq; 1256 if (rann->rann_ttl > 1 && 1257 rann->rann_hopcount < hs->hs_maxhops && 1258 (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 1259 memcpy(&prann, rann, sizeof(prann)); 1260 prann.rann_hopcount += 1; 1261 prann.rann_ttl -= 1; 1262 prann.rann_metric += ms->ms_pmetric->mpm_metric(ni); 1263 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, 1264 broadcastaddr, &prann); 1265 } 1266 } 1267 } 1268 1269 static int 1270 hwmp_send_rann(struct ieee80211_node *ni, 1271 const uint8_t sa[IEEE80211_ADDR_LEN], 1272 const uint8_t da[IEEE80211_ADDR_LEN], 1273 struct ieee80211_meshrann_ie *rann) 1274 { 1275 /* 1276 * mesh rann action frame format 1277 * [6] da 1278 * [6] sa 1279 * [6] addr3 = sa 1280 * [1] action 1281 * [1] category 1282 * [tlv] root annoucement 1283 */ 1284 rann->rann_ie = IEEE80211_ELEMID_MESHRANN; 1285 return hwmp_send_action(ni, sa, da, (uint8_t *)rann, 1286 sizeof(struct ieee80211_meshrann_ie)); 1287 } 1288 1289 #define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 1290 #define PREQ_TADDR(n) preq.preq_targets[n].target_addr 1291 #define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 1292 static struct ieee80211_node * 1293 hwmp_discover(struct ieee80211vap *vap, 1294 const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m) 1295 { 1296 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1297 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1298 struct ieee80211_mesh_route *rt = NULL; 1299 struct ieee80211_hwmp_route *hr; 1300 struct ieee80211_meshpreq_ie preq; 1301 struct ieee80211_node *ni; 1302 int sendpreq = 0; 1303 1304 KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 1305 ("not a mesh vap, opmode %d", vap->iv_opmode)); 1306 1307 KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest), 1308 ("%s: discovering self!", __func__)); 1309 1310 ni = NULL; 1311 if (!IEEE80211_IS_MULTICAST(dest)) { 1312 rt = ieee80211_mesh_rt_find(vap, dest); 1313 if (rt == NULL) { 1314 rt = ieee80211_mesh_rt_add(vap, dest); 1315 if (rt == NULL) { 1316 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 1317 ni, "unable to add discovery path to %6D", 1318 dest, ":"); 1319 vap->iv_stats.is_mesh_rtaddfailed++; 1320 goto done; 1321 } 1322 } 1323 hr = IEEE80211_MESH_ROUTE_PRIV(rt, 1324 struct ieee80211_hwmp_route); 1325 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { 1326 if (hr->hr_origseq == 0) 1327 hr->hr_origseq = ++hs->hs_seq; 1328 rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 1329 rt->rt_lifetime = 1330 ticks_to_msecs(ieee80211_hwmp_pathtimeout); 1331 /* XXX check preq retries */ 1332 sendpreq = 1; 1333 if (m != NULL) { 1334 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, 1335 dest, "%s", 1336 "start path discovery (src <none>)"); 1337 } else { 1338 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, 1339 dest, 1340 "start path discovery (src %6D)", 1341 mtod(m, struct ether_header *)->ether_shost, 1342 ":"); 1343 } 1344 /* 1345 * Try to discover the path for this node. 1346 */ 1347 preq.preq_flags = 0; 1348 preq.preq_hopcount = 0; 1349 preq.preq_ttl = ms->ms_ttl; 1350 preq.preq_id = ++hs->hs_preqid; 1351 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 1352 preq.preq_origseq = hr->hr_origseq; 1353 preq.preq_lifetime = rt->rt_lifetime; 1354 preq.preq_metric = rt->rt_metric; 1355 preq.preq_tcount = 1; 1356 IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest); 1357 PREQ_TFLAGS(0) = 0; 1358 if (ieee80211_hwmp_targetonly) 1359 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO; 1360 if (ieee80211_hwmp_replyforward) 1361 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF; 1362 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN; 1363 PREQ_TSEQ(0) = 0; 1364 /* XXX check return value */ 1365 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, 1366 broadcastaddr, &preq); 1367 } 1368 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) 1369 ni = ieee80211_find_txnode(vap, rt->rt_nexthop); 1370 } else { 1371 ni = ieee80211_find_txnode(vap, dest); 1372 /* NB: if null then we leak mbuf */ 1373 KASSERT(ni != NULL, ("leak mcast frame")); 1374 return ni; 1375 } 1376 done: 1377 if (ni == NULL && m != NULL) { 1378 if (sendpreq) { 1379 struct ieee80211com *ic = vap->iv_ic; 1380 /* 1381 * Queue packet for transmit when path discovery 1382 * completes. If discovery never completes the 1383 * frame will be flushed by way of the aging timer. 1384 */ 1385 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, 1386 "%s", "queue frame until path found"); 1387 m->m_pkthdr.rcvif = (void *)(uintptr_t) 1388 ieee80211_mac_hash(ic, dest); 1389 /* XXX age chosen randomly */ 1390 ieee80211_ageq_append(&ic->ic_stageq, m, 1391 IEEE80211_INACT_WAIT); 1392 } else { 1393 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 1394 dest, NULL, "%s", "no valid path to this node"); 1395 m_freem(m); 1396 } 1397 } 1398 return ni; 1399 } 1400 #undef PREQ_TFLAGS 1401 #undef PREQ_TADDR 1402 #undef PREQ_TSEQ 1403 1404 static int 1405 hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1406 { 1407 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1408 int error; 1409 1410 if (vap->iv_opmode != IEEE80211_M_MBSS) 1411 return ENOSYS; 1412 error = 0; 1413 switch (ireq->i_type) { 1414 case IEEE80211_IOC_HWMP_ROOTMODE: 1415 ireq->i_val = hs->hs_rootmode; 1416 break; 1417 case IEEE80211_IOC_HWMP_MAXHOPS: 1418 ireq->i_val = hs->hs_maxhops; 1419 break; 1420 default: 1421 return ENOSYS; 1422 } 1423 return error; 1424 } 1425 IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211); 1426 1427 static int 1428 hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1429 { 1430 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1431 int error; 1432 1433 if (vap->iv_opmode != IEEE80211_M_MBSS) 1434 return ENOSYS; 1435 error = 0; 1436 switch (ireq->i_type) { 1437 case IEEE80211_IOC_HWMP_ROOTMODE: 1438 if (ireq->i_val < 0 || ireq->i_val > 3) 1439 return EINVAL; 1440 hs->hs_rootmode = ireq->i_val; 1441 hwmp_rootmode_setup(vap); 1442 break; 1443 case IEEE80211_IOC_HWMP_MAXHOPS: 1444 if (ireq->i_val <= 0 || ireq->i_val > 255) 1445 return EINVAL; 1446 hs->hs_maxhops = ireq->i_val; 1447 break; 1448 default: 1449 return ENOSYS; 1450 } 1451 return error; 1452 } 1453 IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211); 1454