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