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