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