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