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