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