ieee80211_hwmp.c revision 230409
1251881Speter/*- 2251881Speter * Copyright (c) 2009 The FreeBSD Foundation 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * This software was developed by Rui Paulo under sponsorship from the 6251881Speter * FreeBSD Foundation. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 17251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27251881Speter * SUCH DAMAGE. 28251881Speter */ 29251881Speter#include <sys/cdefs.h> 30251881Speter#ifdef __FreeBSD__ 31251881Speter__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_hwmp.c 230409 2012-01-21 00:42:28Z adrian $"); 32251881Speter#endif 33251881Speter 34251881Speter/* 35251881Speter * IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP. 36251881Speter * 37251881Speter * Based on March 2009, D3.0 802.11s draft spec. 38251881Speter */ 39251881Speter#include "opt_inet.h" 40251881Speter#include "opt_wlan.h" 41251881Speter 42251881Speter#include <sys/param.h> 43251881Speter#include <sys/systm.h> 44251881Speter#include <sys/mbuf.h> 45251881Speter#include <sys/malloc.h> 46251881Speter#include <sys/kernel.h> 47251881Speter 48251881Speter#include <sys/socket.h> 49251881Speter#include <sys/sockio.h> 50251881Speter#include <sys/endian.h> 51251881Speter#include <sys/errno.h> 52251881Speter#include <sys/proc.h> 53251881Speter#include <sys/sysctl.h> 54251881Speter 55251881Speter#include <net/if.h> 56251881Speter#include <net/if_media.h> 57251881Speter#include <net/if_llc.h> 58251881Speter#include <net/ethernet.h> 59251881Speter 60251881Speter#include <net/bpf.h> 61251881Speter 62251881Speter#include <net80211/ieee80211_var.h> 63251881Speter#include <net80211/ieee80211_action.h> 64251881Speter#include <net80211/ieee80211_input.h> 65251881Speter#include <net80211/ieee80211_mesh.h> 66251881Speter 67251881Speterstatic void hwmp_vattach(struct ieee80211vap *); 68251881Speterstatic void hwmp_vdetach(struct ieee80211vap *); 69251881Speterstatic int hwmp_newstate(struct ieee80211vap *, 70251881Speter enum ieee80211_state, int); 71251881Speterstatic int hwmp_send_action(struct ieee80211_node *, 72251881Speter const uint8_t [IEEE80211_ADDR_LEN], 73251881Speter const uint8_t [IEEE80211_ADDR_LEN], 74251881Speter uint8_t *, size_t); 75251881Speterstatic uint8_t * hwmp_add_meshpreq(uint8_t *, 76251881Speter const struct ieee80211_meshpreq_ie *); 77251881Speterstatic uint8_t * hwmp_add_meshprep(uint8_t *, 78251881Speter const struct ieee80211_meshprep_ie *); 79251881Speterstatic uint8_t * hwmp_add_meshperr(uint8_t *, 80251881Speter const struct ieee80211_meshperr_ie *); 81251881Speterstatic uint8_t * hwmp_add_meshrann(uint8_t *, 82251881Speter const struct ieee80211_meshrann_ie *); 83251881Speterstatic void hwmp_rootmode_setup(struct ieee80211vap *); 84251881Speterstatic void hwmp_rootmode_cb(void *); 85251881Speterstatic void hwmp_rootmode_rann_cb(void *); 86251881Speterstatic void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *, 87251881Speter const struct ieee80211_frame *, 88251881Speter const struct ieee80211_meshpreq_ie *); 89251881Speterstatic int hwmp_send_preq(struct ieee80211_node *, 90251881Speter const uint8_t [IEEE80211_ADDR_LEN], 91251881Speter const uint8_t [IEEE80211_ADDR_LEN], 92251881Speter struct ieee80211_meshpreq_ie *); 93251881Speterstatic void hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *, 94251881Speter const struct ieee80211_frame *, 95251881Speter const struct ieee80211_meshprep_ie *); 96251881Speterstatic int hwmp_send_prep(struct ieee80211_node *, 97251881Speter const uint8_t [IEEE80211_ADDR_LEN], 98251881Speter const uint8_t [IEEE80211_ADDR_LEN], 99251881Speter struct ieee80211_meshprep_ie *); 100251881Speterstatic void hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *, 101251881Speter const struct ieee80211_frame *, 102251881Speter const struct ieee80211_meshperr_ie *); 103251881Speterstatic int hwmp_send_perr(struct ieee80211_node *, 104251881Speter const uint8_t [IEEE80211_ADDR_LEN], 105251881Speter const uint8_t [IEEE80211_ADDR_LEN], 106251881Speter struct ieee80211_meshperr_ie *); 107251881Speterstatic void hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *, 108251881Speter const struct ieee80211_frame *, 109251881Speter const struct ieee80211_meshrann_ie *); 110251881Speterstatic int hwmp_send_rann(struct ieee80211_node *, 111251881Speter const uint8_t [IEEE80211_ADDR_LEN], 112251881Speter const uint8_t [IEEE80211_ADDR_LEN], 113251881Speter struct ieee80211_meshrann_ie *); 114251881Speterstatic struct ieee80211_node * 115251881Speter hwmp_discover(struct ieee80211vap *, 116251881Speter const uint8_t [IEEE80211_ADDR_LEN], struct mbuf *); 117251881Speterstatic void hwmp_peerdown(struct ieee80211_node *); 118251881Speter 119251881Speterstatic struct timeval ieee80211_hwmp_preqminint = { 0, 100000 }; 120251881Speterstatic struct timeval ieee80211_hwmp_perrminint = { 0, 100000 }; 121251881Speter 122251881Speter/* unalligned little endian access */ 123251881Speter#define LE_WRITE_2(p, v) do { \ 124251881Speter ((uint8_t *)(p))[0] = (v) & 0xff; \ 125251881Speter ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 126251881Speter} while (0) 127251881Speter#define LE_WRITE_4(p, v) do { \ 128251881Speter ((uint8_t *)(p))[0] = (v) & 0xff; \ 129251881Speter ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 130251881Speter ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 131251881Speter ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 132251881Speter} while (0) 133251881Speter 134251881Speter 135251881Speter/* NB: the Target Address set in a Proactive PREQ is the broadcast address. */ 136251881Speterstatic const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] = 137251881Speter { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 138251881Speter 139251881Spetertypedef uint32_t ieee80211_hwmp_seq; 140251881Speter#define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0) 141251881Speter#define HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0) 142251881Speter#define HWMP_SEQ_EQ(a, b) ((int32_t)((a)-(b)) == 0) 143251881Speter#define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0) 144251881Speter#define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0) 145251881Speter 146251881Speter/* The longer one of the lifetime should be stored as new lifetime */ 147251881Speter#define MESH_ROUTE_LIFETIME_MAX(a, b) (a > b ? a : b) 148251881Speter 149251881Speter/* 150251881Speter * Private extension of ieee80211_mesh_route. 151251881Speter */ 152251881Speterstruct ieee80211_hwmp_route { 153251881Speter ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/ 154251881Speter ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */ 155251881Speter ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/ 156251881Speter int hr_preqretries; 157251881Speter}; 158251881Speterstruct ieee80211_hwmp_state { 159251881Speter ieee80211_hwmp_seq hs_seq; /* next seq to be used */ 160251881Speter ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */ 161251881Speter struct timeval hs_lastpreq; /* last time we sent a PREQ */ 162251881Speter struct timeval hs_lastperr; /* last time we sent a PERR */ 163251881Speter int hs_rootmode; /* proactive HWMP */ 164251881Speter struct callout hs_roottimer; 165251881Speter uint8_t hs_maxhops; /* max hop count */ 166251881Speter}; 167251881Speter 168251881Speterstatic SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, 169251881Speter "IEEE 802.11s HWMP parameters"); 170251881Speterstatic int ieee80211_hwmp_targetonly = 0; 171251881SpeterSYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, 172251881Speter &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs"); 173251881Speterstatic int ieee80211_hwmp_replyforward = 1; 174251881SpeterSYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW, 175251881Speter &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs"); 176251881Speterstatic int ieee80211_hwmp_pathtimeout = -1; 177251881SpeterSYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW, 178251881Speter &ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 179251881Speter "path entry lifetime (ms)"); 180251881Speterstatic int ieee80211_hwmp_roottimeout = -1; 181251881SpeterSYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW, 182251881Speter &ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I", 183251881Speter "root PREQ timeout (ms)"); 184251881Speterstatic int ieee80211_hwmp_rootint = -1; 185251881SpeterSYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW, 186251881Speter &ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I", 187251881Speter "root interval (ms)"); 188251881Speterstatic int ieee80211_hwmp_rannint = -1; 189251881SpeterSYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW, 190251881Speter &ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I", 191251881Speter "root announcement interval (ms)"); 192251881Speter 193251881Speter#define IEEE80211_HWMP_DEFAULT_MAXHOPS 31 194251881Speter 195251881Speterstatic ieee80211_recv_action_func hwmp_recv_action_meshpath; 196251881Speter 197251881Speterstatic struct ieee80211_mesh_proto_path mesh_proto_hwmp = { 198251881Speter .mpp_descr = "HWMP", 199251881Speter .mpp_ie = IEEE80211_MESHCONF_PATH_HWMP, 200251881Speter .mpp_discover = hwmp_discover, 201251881Speter .mpp_peerdown = hwmp_peerdown, 202251881Speter .mpp_vattach = hwmp_vattach, 203251881Speter .mpp_vdetach = hwmp_vdetach, 204251881Speter .mpp_newstate = hwmp_newstate, 205251881Speter .mpp_privlen = sizeof(struct ieee80211_hwmp_route), 206251881Speter}; 207251881SpeterSYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW, 208251881Speter &mesh_proto_hwmp.mpp_inact, 0, ieee80211_sysctl_msecs_ticks, "I", 209251881Speter "mesh route inactivity timeout (ms)"); 210251881Speter 211251881Speter 212251881Speterstatic void 213251881Speterieee80211_hwmp_init(void) 214251881Speter{ 215251881Speter ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000); 216251881Speter ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000); 217251881Speter ieee80211_hwmp_rootint = msecs_to_ticks(2*1000); 218251881Speter ieee80211_hwmp_rannint = msecs_to_ticks(1*1000); 219251881Speter 220251881Speter /* 221251881Speter * Register action frame handler. 222251881Speter */ 223251881Speter ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH, 224251881Speter IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath); 225251881Speter 226251881Speter /* NB: default is 5 secs per spec */ 227251881Speter mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000); 228251881Speter 229251881Speter /* 230251881Speter * Register HWMP. 231251881Speter */ 232251881Speter ieee80211_mesh_register_proto_path(&mesh_proto_hwmp); 233251881Speter} 234251881SpeterSYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL); 235251881Speter 236251881Spetervoid 237251881Speterhwmp_vattach(struct ieee80211vap *vap) 238251881Speter{ 239251881Speter struct ieee80211_hwmp_state *hs; 240251881Speter 241251881Speter KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 242251881Speter ("not a mesh vap, opmode %d", vap->iv_opmode)); 243251881Speter 244251881Speter hs = malloc(sizeof(struct ieee80211_hwmp_state), M_80211_VAP, 245251881Speter M_NOWAIT | M_ZERO); 246251881Speter if (hs == NULL) { 247251881Speter printf("%s: couldn't alloc HWMP state\n", __func__); 248251881Speter return; 249251881Speter } 250251881Speter hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS; 251251881Speter callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE); 252251881Speter vap->iv_hwmp = hs; 253251881Speter} 254251881Speter 255251881Spetervoid 256251881Speterhwmp_vdetach(struct ieee80211vap *vap) 257251881Speter{ 258251881Speter struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 259251881Speter 260251881Speter callout_drain(&hs->hs_roottimer); 261251881Speter free(vap->iv_hwmp, M_80211_VAP); 262251881Speter vap->iv_hwmp = NULL; 263251881Speter} 264251881Speter 265251881Speterint 266251881Speterhwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg) 267251881Speter{ 268251881Speter enum ieee80211_state nstate = vap->iv_state; 269251881Speter struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 270251881Speter 271251881Speter IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", 272251881Speter __func__, ieee80211_state_name[ostate], 273251881Speter ieee80211_state_name[nstate], arg); 274251881Speter 275251881Speter if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) 276251881Speter callout_drain(&hs->hs_roottimer); 277251881Speter if (nstate == IEEE80211_S_RUN) 278251881Speter hwmp_rootmode_setup(vap); 279251881Speter return 0; 280251881Speter} 281251881Speter 282251881Speterstatic int 283251881Speterhwmp_recv_action_meshpath(struct ieee80211_node *ni, 284251881Speter const struct ieee80211_frame *wh, 285251881Speter const uint8_t *frm, const uint8_t *efrm) 286251881Speter{ 287251881Speter struct ieee80211vap *vap = ni->ni_vap; 288251881Speter struct ieee80211_meshpreq_ie preq; 289251881Speter struct ieee80211_meshprep_ie prep; 290251881Speter struct ieee80211_meshperr_ie perr; 291251881Speter struct ieee80211_meshrann_ie rann; 292251881Speter const uint8_t *iefrm = frm + 2; /* action + code */ 293251881Speter int found = 0; 294251881Speter 295251881Speter while (efrm - iefrm > 1) { 296251881Speter IEEE80211_VERIFY_LENGTH(efrm - iefrm, iefrm[1] + 2, return 0); 297251881Speter switch (*iefrm) { 298251881Speter case IEEE80211_ELEMID_MESHPREQ: 299251881Speter { 300251881Speter const struct ieee80211_meshpreq_ie *mpreq = 301251881Speter (const struct ieee80211_meshpreq_ie *) iefrm; 302251881Speter /* XXX > 1 target */ 303251881Speter if (mpreq->preq_len != 304251881Speter sizeof(struct ieee80211_meshpreq_ie) - 2) { 305251881Speter IEEE80211_DISCARD(vap, 306251881Speter IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 307251881Speter wh, NULL, "%s", "PREQ with wrong len"); 308251881Speter vap->iv_stats.is_rx_mgtdiscard++; 309251881Speter break; 310251881Speter } 311251881Speter memcpy(&preq, mpreq, sizeof(preq)); 312251881Speter preq.preq_id = LE_READ_4(&mpreq->preq_id); 313251881Speter preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq); 314251881Speter preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime); 315251881Speter preq.preq_metric = LE_READ_4(&mpreq->preq_metric); 316251881Speter preq.preq_targets[0].target_seq = 317251881Speter LE_READ_4(&mpreq->preq_targets[0].target_seq); 318251881Speter hwmp_recv_preq(vap, ni, wh, &preq); 319251881Speter found++; 320251881Speter break; 321251881Speter } 322251881Speter case IEEE80211_ELEMID_MESHPREP: 323251881Speter { 324251881Speter const struct ieee80211_meshprep_ie *mprep = 325251881Speter (const struct ieee80211_meshprep_ie *) iefrm; 326251881Speter if (mprep->prep_len != 327251881Speter sizeof(struct ieee80211_meshprep_ie) - 2) { 328251881Speter IEEE80211_DISCARD(vap, 329251881Speter IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 330251881Speter wh, NULL, "%s", "PREP with wrong len"); 331251881Speter vap->iv_stats.is_rx_mgtdiscard++; 332251881Speter break; 333251881Speter } 334251881Speter memcpy(&prep, mprep, sizeof(prep)); 335251881Speter prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq); 336251881Speter prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime); 337251881Speter prep.prep_metric = LE_READ_4(&mprep->prep_metric); 338251881Speter prep.prep_origseq = LE_READ_4(&mprep->prep_origseq); 339251881Speter hwmp_recv_prep(vap, ni, wh, &prep); 340251881Speter found++; 341251881Speter break; 342251881Speter } 343251881Speter case IEEE80211_ELEMID_MESHPERR: 344251881Speter { 345251881Speter const struct ieee80211_meshperr_ie *mperr = 346251881Speter (const struct ieee80211_meshperr_ie *) iefrm; 347251881Speter /* XXX > 1 target */ 348251881Speter if (mperr->perr_len != 349251881Speter sizeof(struct ieee80211_meshperr_ie) - 2) { 350251881Speter IEEE80211_DISCARD(vap, 351251881Speter IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 352251881Speter wh, NULL, "%s", "PERR with wrong len"); 353251881Speter vap->iv_stats.is_rx_mgtdiscard++; 354251881Speter break; 355251881Speter } 356251881Speter memcpy(&perr, mperr, sizeof(perr)); 357251881Speter perr.perr_dests[0].dest_seq = 358 LE_READ_4(&mperr->perr_dests[0].dest_seq); 359 hwmp_recv_perr(vap, ni, wh, &perr); 360 found++; 361 break; 362 } 363 case IEEE80211_ELEMID_MESHRANN: 364 { 365 const struct ieee80211_meshrann_ie *mrann = 366 (const struct ieee80211_meshrann_ie *) iefrm; 367 if (mrann->rann_len != 368 sizeof(struct ieee80211_meshrann_ie) - 2) { 369 IEEE80211_DISCARD(vap, 370 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 371 wh, NULL, "%s", "RAN with wrong len"); 372 vap->iv_stats.is_rx_mgtdiscard++; 373 return 1; 374 } 375 memcpy(&rann, mrann, sizeof(rann)); 376 rann.rann_seq = LE_READ_4(&mrann->rann_seq); 377 rann.rann_metric = LE_READ_4(&mrann->rann_metric); 378 hwmp_recv_rann(vap, ni, wh, &rann); 379 found++; 380 break; 381 } 382 } 383 iefrm += iefrm[1] + 2; 384 } 385 if (!found) { 386 IEEE80211_DISCARD(vap, 387 IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP, 388 wh, NULL, "%s", "PATH SEL action without IE"); 389 vap->iv_stats.is_rx_mgtdiscard++; 390 } 391 return 0; 392} 393 394static int 395hwmp_send_action(struct ieee80211_node *ni, 396 const uint8_t sa[IEEE80211_ADDR_LEN], 397 const uint8_t da[IEEE80211_ADDR_LEN], 398 uint8_t *ie, size_t len) 399{ 400 struct ieee80211vap *vap = ni->ni_vap; 401 struct ieee80211com *ic = ni->ni_ic; 402 struct ieee80211_bpf_params params; 403 struct mbuf *m; 404 uint8_t *frm; 405 406 if (vap->iv_state == IEEE80211_S_CAC) { 407 IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 408 "block %s frame in CAC state", "HWMP action"); 409 vap->iv_stats.is_tx_badstate++; 410 return EIO; /* XXX */ 411 } 412 413 KASSERT(ni != NULL, ("null node")); 414 /* 415 * Hold a reference on the node so it doesn't go away until after 416 * the xmit is complete all the way in the driver. On error we 417 * will remove our reference. 418 */ 419#ifdef IEEE80211_DEBUG_REFCNT 420 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 421 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 422 __func__, __LINE__, 423 ni, ether_sprintf(ni->ni_macaddr), 424 ieee80211_node_refcnt(ni)+1); 425#endif 426 ieee80211_ref_node(ni); 427 428 m = ieee80211_getmgtframe(&frm, 429 ic->ic_headroom + sizeof(struct ieee80211_frame), 430 sizeof(struct ieee80211_action) + len 431 ); 432 if (m == NULL) { 433 ieee80211_free_node(ni); 434 vap->iv_stats.is_tx_nobuf++; 435 return ENOMEM; 436 } 437 *frm++ = IEEE80211_ACTION_CAT_MESHPATH; 438 *frm++ = IEEE80211_ACTION_MESHPATH_SEL; 439 switch (*ie) { 440 case IEEE80211_ELEMID_MESHPREQ: 441 frm = hwmp_add_meshpreq(frm, 442 (struct ieee80211_meshpreq_ie *)ie); 443 break; 444 case IEEE80211_ELEMID_MESHPREP: 445 frm = hwmp_add_meshprep(frm, 446 (struct ieee80211_meshprep_ie *)ie); 447 break; 448 case IEEE80211_ELEMID_MESHPERR: 449 frm = hwmp_add_meshperr(frm, 450 (struct ieee80211_meshperr_ie *)ie); 451 break; 452 case IEEE80211_ELEMID_MESHRANN: 453 frm = hwmp_add_meshrann(frm, 454 (struct ieee80211_meshrann_ie *)ie); 455 break; 456 } 457 458 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 459 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 460 if (m == NULL) { 461 ieee80211_free_node(ni); 462 vap->iv_stats.is_tx_nobuf++; 463 return ENOMEM; 464 } 465 ieee80211_send_setup(ni, m, 466 IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION, 467 IEEE80211_NONQOS_TID, sa, da, sa); 468 469 m->m_flags |= M_ENCAP; /* mark encapsulated */ 470 IEEE80211_NODE_STAT(ni, tx_mgmt); 471 472 memset(¶ms, 0, sizeof(params)); 473 params.ibp_pri = WME_AC_VO; 474 params.ibp_rate0 = ni->ni_txparms->mgmtrate; 475 if (IEEE80211_IS_MULTICAST(da)) 476 params.ibp_try0 = 1; 477 else 478 params.ibp_try0 = ni->ni_txparms->maxretry; 479 params.ibp_power = ni->ni_txpower; 480 return ic->ic_raw_xmit(ni, m, ¶ms); 481} 482 483#define ADDSHORT(frm, v) do { \ 484 frm[0] = (v) & 0xff; \ 485 frm[1] = (v) >> 8; \ 486 frm += 2; \ 487} while (0) 488#define ADDWORD(frm, v) do { \ 489 LE_WRITE_4(frm, v); \ 490 frm += 4; \ 491} while (0) 492/* 493 * Add a Mesh Path Request IE to a frame. 494 */ 495static uint8_t * 496hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq) 497{ 498 int i; 499 500 *frm++ = IEEE80211_ELEMID_MESHPREQ; 501 *frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 + 502 (preq->preq_tcount - 1) * sizeof(*preq->preq_targets); 503 *frm++ = preq->preq_flags; 504 *frm++ = preq->preq_hopcount; 505 *frm++ = preq->preq_ttl; 506 ADDWORD(frm, preq->preq_id); 507 IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6; 508 ADDWORD(frm, preq->preq_origseq); 509 ADDWORD(frm, preq->preq_lifetime); 510 ADDWORD(frm, preq->preq_metric); 511 *frm++ = preq->preq_tcount; 512 for (i = 0; i < preq->preq_tcount; i++) { 513 *frm++ = preq->preq_targets[i].target_flags; 514 IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr); 515 frm += 6; 516 ADDWORD(frm, preq->preq_targets[i].target_seq); 517 } 518 return frm; 519} 520 521/* 522 * Add a Mesh Path Reply IE to a frame. 523 */ 524static uint8_t * 525hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep) 526{ 527 *frm++ = IEEE80211_ELEMID_MESHPREP; 528 *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2; 529 *frm++ = prep->prep_flags; 530 *frm++ = prep->prep_hopcount; 531 *frm++ = prep->prep_ttl; 532 IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6; 533 ADDWORD(frm, prep->prep_targetseq); 534 ADDWORD(frm, prep->prep_lifetime); 535 ADDWORD(frm, prep->prep_metric); 536 IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6; 537 ADDWORD(frm, prep->prep_origseq); 538 return frm; 539} 540 541/* 542 * Add a Mesh Path Error IE to a frame. 543 */ 544static uint8_t * 545hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr) 546{ 547 int i; 548 549 *frm++ = IEEE80211_ELEMID_MESHPERR; 550 *frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 + 551 (perr->perr_ndests - 1) * sizeof(*perr->perr_dests); 552 *frm++ = perr->perr_ttl; 553 *frm++ = perr->perr_ndests; 554 for (i = 0; i < perr->perr_ndests; i++) { 555 *frm++ = perr->perr_dests[i].dest_flags; 556 IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr); 557 frm += 6; 558 ADDWORD(frm, perr->perr_dests[i].dest_seq); 559 ADDSHORT(frm, perr->perr_dests[i].dest_rcode); 560 } 561 return frm; 562} 563 564/* 565 * Add a Root Annoucement IE to a frame. 566 */ 567static uint8_t * 568hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann) 569{ 570 *frm++ = IEEE80211_ELEMID_MESHRANN; 571 *frm++ = sizeof(struct ieee80211_meshrann_ie) - 2; 572 *frm++ = rann->rann_flags; 573 *frm++ = rann->rann_hopcount; 574 *frm++ = rann->rann_ttl; 575 IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6; 576 ADDWORD(frm, rann->rann_seq); 577 ADDWORD(frm, rann->rann_metric); 578 return frm; 579} 580 581static void 582hwmp_rootmode_setup(struct ieee80211vap *vap) 583{ 584 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 585 586 switch (hs->hs_rootmode) { 587 case IEEE80211_HWMP_ROOTMODE_DISABLED: 588 callout_drain(&hs->hs_roottimer); 589 break; 590 case IEEE80211_HWMP_ROOTMODE_NORMAL: 591 case IEEE80211_HWMP_ROOTMODE_PROACTIVE: 592 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint, 593 hwmp_rootmode_cb, vap); 594 break; 595 case IEEE80211_HWMP_ROOTMODE_RANN: 596 callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint, 597 hwmp_rootmode_rann_cb, vap); 598 break; 599 } 600} 601 602/* 603 * Send a broadcast Path Request to find all nodes on the mesh. We are 604 * called when the vap is configured as a HWMP root node. 605 */ 606#define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 607#define PREQ_TADDR(n) preq.preq_targets[n].target_addr 608#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 609static void 610hwmp_rootmode_cb(void *arg) 611{ 612 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 613 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 614 struct ieee80211_mesh_state *ms = vap->iv_mesh; 615 struct ieee80211_meshpreq_ie preq; 616 617 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 618 "%s", "send broadcast PREQ"); 619 620 preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; 621 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 622 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR; 623 if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE) 624 preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP; 625 preq.preq_hopcount = 0; 626 preq.preq_ttl = ms->ms_ttl; 627 preq.preq_id = ++hs->hs_preqid; 628 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 629 preq.preq_origseq = ++hs->hs_seq; 630 preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout); 631 preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 632 preq.preq_tcount = 1; 633 IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr); 634 PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO | 635 IEEE80211_MESHPREQ_TFLAGS_RF; 636 PREQ_TSEQ(0) = 0; 637 vap->iv_stats.is_hwmp_rootreqs++; 638 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq); 639 hwmp_rootmode_setup(vap); 640} 641#undef PREQ_TFLAGS 642#undef PREQ_TADDR 643#undef PREQ_TSEQ 644 645/* 646 * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are 647 * called when the vap is configured as a HWMP RANN root node. 648 */ 649static void 650hwmp_rootmode_rann_cb(void *arg) 651{ 652 struct ieee80211vap *vap = (struct ieee80211vap *)arg; 653 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 654 struct ieee80211_mesh_state *ms = vap->iv_mesh; 655 struct ieee80211_meshrann_ie rann; 656 657 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, 658 "%s", "send broadcast RANN"); 659 660 rann.rann_flags = 0; 661 if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) 662 rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR; 663 rann.rann_hopcount = 0; 664 rann.rann_ttl = ms->ms_ttl; 665 IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr); 666 rann.rann_seq = ++hs->hs_seq; 667 rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 668 669 vap->iv_stats.is_hwmp_rootrann++; 670 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann); 671 hwmp_rootmode_setup(vap); 672} 673 674#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags 675#define PREQ_TADDR(n) preq->preq_targets[n].target_addr 676#define PREQ_TSEQ(n) preq->preq_targets[n].target_seq 677static void 678hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, 679 const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq) 680{ 681 struct ieee80211_mesh_state *ms = vap->iv_mesh; 682 struct ieee80211_mesh_route *rt = NULL; 683 struct ieee80211_mesh_route *rtorig = NULL; 684 struct ieee80211_mesh_route *rttarg = NULL; 685 struct ieee80211_hwmp_route *hrorig = NULL; 686 struct ieee80211_hwmp_route *hrtarg = NULL; 687 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 688 struct ieee80211_meshprep_ie prep; 689 690 if (ni == vap->iv_bss || 691 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 692 return; 693 /* 694 * Ignore PREQs from us. Could happen because someone forward it 695 * back to us. 696 */ 697 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr)) 698 return; 699 700 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 701 "received PREQ, source %6D", preq->preq_origaddr, ":"); 702 703 /* 704 * Acceptance criteria: if the PREQ is not for us or not broadcast 705 * AND forwarding is disabled, discard this PREQ. 706 * XXX: need to check PROXY 707 */ 708 if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) || 709 !IEEE80211_IS_MULTICAST(PREQ_TADDR(0))) && 710 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 711 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 712 preq->preq_origaddr, NULL, "%s", "not accepting PREQ"); 713 return; 714 } 715 /* 716 * Acceptance criteria: if unicast addressed 717 * AND no valid forwarding for Target of PREQ, discard this PREQ. 718 */ 719 rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); 720 if(rttarg != NULL) 721 hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg, 722 struct ieee80211_hwmp_route); 723 /* Address mode: ucast */ 724 if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 && 725 rttarg == NULL && 726 !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { 727 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 728 preq->preq_origaddr, NULL, 729 "unicast addressed PREQ of unknown target %6D", 730 PREQ_TADDR(0), ":"); 731 return; 732 } 733 734 /* PREQ ACCEPTED */ 735 736 rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); 737 if (rtorig == NULL) { 738 rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr); 739 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 740 "adding originator %6D", preq->preq_origaddr, ":"); 741 } 742 if (rtorig == NULL) { 743 /* XXX stat */ 744 return; 745 } 746 hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route); 747 748 /* Data creation and update of forwarding information 749 * according to Table 11C-8 for originator mesh STA. 750 */ 751 if(HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) || 752 (HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) && 753 preq->preq_metric < rtorig->rt_metric)) { 754 hrorig->hr_seq = preq->preq_origseq; 755 IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2); 756 rtorig->rt_metric = preq->preq_metric + 757 ms->ms_pmetric->mpm_metric(ni); 758 rtorig->rt_nhops = preq->preq_hopcount + 1; 759 rtorig->rt_lifetime = MESH_ROUTE_LIFETIME_MAX( 760 preq->preq_lifetime, rtorig->rt_lifetime); 761 /* path to orig is valid now */ 762 rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 763 }else if(hrtarg != NULL && 764 HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0)) && 765 (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { 766 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 767 "discard PREQ from %6D, old seq no %u <= %u", 768 preq->preq_origaddr, ":", 769 preq->preq_origseq, hrorig->hr_seq); 770 return; 771 } 772 773 /* 774 * Forwarding information for transmitter mesh STA 775 * [OPTIONAL: if metric improved] 776 */ 777 778 /* 779 * Check if the PREQ is addressed to us. 780 */ 781 if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { 782 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 783 "reply to %6D", preq->preq_origaddr, ":"); 784 /* 785 * Build and send a PREP frame. 786 */ 787 prep.prep_flags = 0; 788 prep.prep_hopcount = 0; 789 prep.prep_ttl = ms->ms_ttl; 790 IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr); 791 prep.prep_targetseq = ++hs->hs_seq; 792 prep.prep_lifetime = preq->preq_lifetime; 793 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 794 IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr); 795 prep.prep_origseq = preq->preq_origseq; 796 hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep); 797 /* 798 * Build the reverse path, if we don't have it already. 799 */ 800 rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); 801 if (rt == NULL) 802 hwmp_discover(vap, preq->preq_origaddr, NULL); 803 else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) 804 hwmp_discover(vap, rt->rt_dest, NULL); 805 return; 806 } 807 /* 808 * Proactive PREQ: reply with a proactive PREP to the 809 * root STA if requested. 810 */ 811 if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) && 812 (PREQ_TFLAGS(0) & 813 ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) == 814 (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) { 815 uint8_t rootmac[IEEE80211_ADDR_LEN]; 816 817 IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr); 818 rt = ieee80211_mesh_rt_find(vap, rootmac); 819 if (rt == NULL) { 820 rt = ieee80211_mesh_rt_add(vap, rootmac); 821 if (rt == NULL) { 822 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 823 "unable to add root mesh path to %6D", 824 rootmac, ":"); 825 vap->iv_stats.is_mesh_rtaddfailed++; 826 return; 827 } 828 } 829 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 830 "root mesh station @ %6D", rootmac, ":"); 831 832 /* 833 * Reply with a PREP if we don't have a path to the root 834 * or if the root sent us a proactive PREQ. 835 */ 836 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || 837 (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) { 838 prep.prep_flags = 0; 839 prep.prep_hopcount = 0; 840 prep.prep_ttl = ms->ms_ttl; 841 IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac); 842 prep.prep_origseq = preq->preq_origseq; 843 prep.prep_lifetime = preq->preq_lifetime; 844 prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 845 IEEE80211_ADDR_COPY(prep.prep_targetaddr, 846 vap->iv_myaddr); 847 prep.prep_targetseq = ++hs->hs_seq; 848 hwmp_send_prep(vap->iv_bss, vap->iv_myaddr, 849 broadcastaddr, &prep); 850 } 851 hwmp_discover(vap, rootmac, NULL); 852 return; 853 } 854 rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); 855 856 /* 857 * Forwarding and Intermediate reply for PREQs with 1 target. 858 */ 859 if (preq->preq_tcount == 1) { 860 struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */ 861 862 memcpy(&ppreq, preq, sizeof(ppreq)); 863 /* 864 * We have a valid route to this node. 865 */ 866 if (rt != NULL && 867 (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { 868 if (preq->preq_ttl > 1 && 869 preq->preq_hopcount < hs->hs_maxhops) { 870 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 871 "forward PREQ from %6D", 872 preq->preq_origaddr, ":"); 873 /* 874 * Propagate the original PREQ. 875 * PREQ is unicast now to rt->rt_nexthop 876 */ 877 ppreq.preq_flags &= 878 ~IEEE80211_MESHPREQ_FLAGS_AM; 879 ppreq.preq_hopcount += 1; 880 ppreq.preq_ttl -= 1; 881 ppreq.preq_metric += 882 ms->ms_pmetric->mpm_metric(ni); 883 /* 884 * Set TO and unset RF bits because we are 885 * going to send a PREP next. 886 */ 887 ppreq.preq_targets[0].target_flags |= 888 IEEE80211_MESHPREQ_TFLAGS_TO; 889 ppreq.preq_targets[0].target_flags &= 890 ~IEEE80211_MESHPREQ_TFLAGS_RF; 891 hwmp_send_preq(ni, vap->iv_myaddr, 892 rt->rt_nexthop, &ppreq); 893 } 894 /* 895 * Check if we can send an intermediate Path Reply, 896 * i.e., Target Only bit is not set. 897 */ 898 if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) { 899 struct ieee80211_meshprep_ie prep; 900 901 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 902 "intermediate reply for PREQ from %6D", 903 preq->preq_origaddr, ":"); 904 prep.prep_flags = 0; 905 prep.prep_hopcount = rt->rt_nhops + 1; 906 prep.prep_ttl = ms->ms_ttl; 907 IEEE80211_ADDR_COPY(&prep.prep_targetaddr, 908 PREQ_TADDR(0)); 909 prep.prep_targetseq = hrorig->hr_seq; 910 prep.prep_lifetime = preq->preq_lifetime; 911 prep.prep_metric = rt->rt_metric + 912 ms->ms_pmetric->mpm_metric(ni); 913 IEEE80211_ADDR_COPY(&prep.prep_origaddr, 914 preq->preq_origaddr); 915 prep.prep_origseq = hrorig->hr_seq; 916 hwmp_send_prep(ni, vap->iv_myaddr, 917 broadcastaddr, &prep); 918 } 919 /* 920 * We have no information about this path, 921 * propagate the PREQ. 922 */ 923 } else if (preq->preq_ttl > 1 && 924 preq->preq_hopcount < hs->hs_maxhops) { 925 if (rt == NULL) { 926 rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0)); 927 if (rt == NULL) { 928 IEEE80211_NOTE(vap, 929 IEEE80211_MSG_HWMP, ni, 930 "unable to add PREQ path to %6D", 931 PREQ_TADDR(0), ":"); 932 vap->iv_stats.is_mesh_rtaddfailed++; 933 return; 934 } 935 } 936 rt->rt_metric = preq->preq_metric; 937 rt->rt_lifetime = preq->preq_lifetime; 938 hrorig = IEEE80211_MESH_ROUTE_PRIV(rt, 939 struct ieee80211_hwmp_route); 940 hrorig->hr_seq = preq->preq_origseq; 941 hrorig->hr_preqid = preq->preq_id; 942 943 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 944 "forward PREQ from %6D", 945 preq->preq_origaddr, ":"); 946 ppreq.preq_hopcount += 1; 947 ppreq.preq_ttl -= 1; 948 ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); 949 hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr, 950 &ppreq); 951 } 952 } 953} 954#undef PREQ_TFLAGS 955#undef PREQ_TADDR 956#undef PREQ_TSEQ 957 958static int 959hwmp_send_preq(struct ieee80211_node *ni, 960 const uint8_t sa[IEEE80211_ADDR_LEN], 961 const uint8_t da[IEEE80211_ADDR_LEN], 962 struct ieee80211_meshpreq_ie *preq) 963{ 964 struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; 965 966 /* 967 * Enforce PREQ interval. 968 */ 969 if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0) 970 return EALREADY; 971 getmicrouptime(&hs->hs_lastpreq); 972 973 /* 974 * mesh preq action frame format 975 * [6] da 976 * [6] sa 977 * [6] addr3 = sa 978 * [1] action 979 * [1] category 980 * [tlv] mesh path request 981 */ 982 preq->preq_ie = IEEE80211_ELEMID_MESHPREQ; 983 return hwmp_send_action(ni, sa, da, (uint8_t *)preq, 984 sizeof(struct ieee80211_meshpreq_ie)); 985} 986 987static void 988hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, 989 const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep) 990{ 991 struct ieee80211_mesh_state *ms = vap->iv_mesh; 992 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 993 struct ieee80211_mesh_route *rt = NULL; 994 struct ieee80211_hwmp_route *hr; 995 struct ieee80211com *ic = vap->iv_ic; 996 struct ifnet *ifp = vap->iv_ifp; 997 struct mbuf *m, *next; 998 uint32_t metric = 0; 999 1000 /* 1001 * Acceptance criteria: if the corresponding PREQ was not generated 1002 * by us and forwarding is disabled, discard this PREP. 1003 */ 1004 if (ni == vap->iv_bss || 1005 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) 1006 return; 1007 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && 1008 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) 1009 return; 1010 1011 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1012 "received PREP from %6D", prep->prep_targetaddr, ":"); 1013 1014 rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr); 1015 if (rt == NULL) { 1016 /* 1017 * If we have no entry this could be a reply to a root PREQ. 1018 * XXX: not true anymore cause we dont create entry for target 1019 * when propagating PREQs like the old code did. 1020 */ 1021 if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) { 1022 rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr); 1023 if (rt == NULL) { 1024 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 1025 ni, "unable to add PREP path to %6D", 1026 prep->prep_targetaddr, ":"); 1027 vap->iv_stats.is_mesh_rtaddfailed++; 1028 return; 1029 } 1030 IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); 1031 rt->rt_nhops = prep->prep_hopcount; 1032 rt->rt_lifetime = prep->prep_lifetime; 1033 rt->rt_metric = prep->prep_metric; 1034 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 1035 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1036 "add root path to %6D nhops %d metric %lu (PREP)", 1037 prep->prep_targetaddr, ":", 1038 rt->rt_nhops, rt->rt_metric); 1039 return; 1040 } 1041 return; 1042 } 1043 /* 1044 * Sequence number validation. 1045 */ 1046 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1047 if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) { 1048 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1049 "discard PREP from %6D, old seq no %u <= %u", 1050 prep->prep_targetaddr, ":", 1051 prep->prep_targetseq, hr->hr_seq); 1052 return; 1053 } 1054 1055 hr->hr_seq = prep->prep_targetseq; 1056 /* 1057 * If it's NOT for us, propagate the PREP. 1058 */ 1059 if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && 1060 prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) { 1061 struct ieee80211_meshprep_ie pprep; /* propagated PREP */ 1062 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1063 "propagate PREP from %6D", 1064 prep->prep_targetaddr, ":"); 1065 1066 memcpy(&pprep, prep, sizeof(pprep)); 1067 pprep.prep_hopcount += 1; 1068 pprep.prep_ttl -= 1; 1069 pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni); 1070 hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep); 1071 } 1072 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1073 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 1074 /* NB: never clobber a proxy entry */; 1075 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1076 "discard PREP for %6D, route is marked PROXY", 1077 prep->prep_targetaddr, ":"); 1078 vap->iv_stats.is_hwmp_proxy++; 1079 /* NB: first path discovery always fails */ 1080 } else if (hr->hr_origseq == 0 || 1081 prep->prep_origseq == hr->hr_origseq) { 1082 /* 1083 * Check if we already have a path to this node. 1084 * If we do, check if this path reply contains a 1085 * better route. 1086 */ 1087 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || 1088 (prep->prep_hopcount < rt->rt_nhops || 1089 prep->prep_metric < rt->rt_metric)) { 1090 hr->hr_origseq = prep->prep_origseq; 1091 metric = prep->prep_metric + 1092 ms->ms_pmetric->mpm_metric(ni); 1093 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1094 "%s path to %6D, hopcount %d:%d metric %d:%d", 1095 rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ? 1096 "prefer" : "update", 1097 prep->prep_origaddr, ":", 1098 rt->rt_nhops, prep->prep_hopcount, 1099 rt->rt_metric, prep->prep_metric); 1100 IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); 1101 rt->rt_nhops = prep->prep_hopcount + 1; 1102 rt->rt_lifetime = prep->prep_lifetime; 1103 rt->rt_metric = metric; 1104 rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; 1105 } else { 1106 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1107 "ignore PREP for %6D, hopcount %d:%d metric %d:%d", 1108 prep->prep_targetaddr, ":", 1109 rt->rt_nhops, prep->prep_hopcount, 1110 rt->rt_metric, prep->prep_metric); 1111 } 1112 } else { 1113 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1114 "discard PREP for %6D, wrong orig seqno %u != %u", 1115 prep->prep_targetaddr, ":", prep->prep_origseq, 1116 hr->hr_origseq); 1117 vap->iv_stats.is_hwmp_wrongseq++; 1118 } 1119 /* 1120 * Check for frames queued awaiting path discovery. 1121 * XXX probably can tell exactly and avoid remove call 1122 * NB: hash may have false matches, if so they will get 1123 * stuck back on the stageq because there won't be 1124 * a path. 1125 */ 1126 m = ieee80211_ageq_remove(&ic->ic_stageq, 1127 (struct ieee80211_node *)(uintptr_t) 1128 ieee80211_mac_hash(ic, rt->rt_dest)); 1129 for (; m != NULL; m = next) { 1130 next = m->m_nextpkt; 1131 m->m_nextpkt = NULL; 1132 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1133 "flush queued frame %p len %d", m, m->m_pkthdr.len); 1134 ifp->if_transmit(ifp, m); 1135 } 1136} 1137 1138static int 1139hwmp_send_prep(struct ieee80211_node *ni, 1140 const uint8_t sa[IEEE80211_ADDR_LEN], 1141 const uint8_t da[IEEE80211_ADDR_LEN], 1142 struct ieee80211_meshprep_ie *prep) 1143{ 1144 /* NB: there's no PREP minimum interval. */ 1145 1146 /* 1147 * mesh prep action frame format 1148 * [6] da 1149 * [6] sa 1150 * [6] addr3 = sa 1151 * [1] action 1152 * [1] category 1153 * [tlv] mesh path reply 1154 */ 1155 prep->prep_ie = IEEE80211_ELEMID_MESHPREP; 1156 return hwmp_send_action(ni, sa, da, (uint8_t *)prep, 1157 sizeof(struct ieee80211_meshprep_ie)); 1158} 1159 1160#define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags 1161#define PERR_DADDR(n) perr.perr_dests[n].dest_addr 1162#define PERR_DSEQ(n) perr.perr_dests[n].dest_seq 1163#define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode 1164static void 1165hwmp_peerdown(struct ieee80211_node *ni) 1166{ 1167 struct ieee80211vap *vap = ni->ni_vap; 1168 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1169 struct ieee80211_meshperr_ie perr; 1170 struct ieee80211_mesh_route *rt; 1171 struct ieee80211_hwmp_route *hr; 1172 1173 rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr); 1174 if (rt == NULL) 1175 return; 1176 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1177 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1178 "%s", "delete route entry"); 1179 perr.perr_ttl = ms->ms_ttl; 1180 perr.perr_ndests = 1; 1181 PERR_DFLAGS(0) = 0; 1182 if (hr->hr_seq == 0) 1183 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN; 1184 PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC; 1185 IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest); 1186 PERR_DSEQ(0) = hr->hr_seq; 1187 PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH; 1188 /* NB: flush everything passing through peer */ 1189 ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr); 1190 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr); 1191} 1192#undef PERR_DFLAGS 1193#undef PERR_DADDR 1194#undef PERR_DSEQ 1195#undef PERR_DRCODE 1196 1197#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags 1198#define PERR_DADDR(n) perr->perr_dests[n].dest_addr 1199#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq 1200#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode 1201static void 1202hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni, 1203 const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr) 1204{ 1205 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1206 struct ieee80211_mesh_route *rt = NULL; 1207 struct ieee80211_hwmp_route *hr; 1208 struct ieee80211_meshperr_ie pperr; 1209 int i, forward = 0; 1210 1211 /* 1212 * Acceptance criteria: check if we received a PERR from a 1213 * neighbor and forwarding is enabled. 1214 */ 1215 if (ni == vap->iv_bss || 1216 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1217 !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) 1218 return; 1219 /* 1220 * Find all routing entries that match and delete them. 1221 */ 1222 for (i = 0; i < perr->perr_ndests; i++) { 1223 rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i)); 1224 if (rt == NULL) 1225 continue; 1226 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1227 if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) && 1228 HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) { 1229 ieee80211_mesh_rt_del(vap, rt->rt_dest); 1230 ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest); 1231 rt = NULL; 1232 forward = 1; 1233 } 1234 } 1235 /* 1236 * Propagate the PERR if we previously found it on our routing table. 1237 * XXX handle ndest > 1 1238 */ 1239 if (forward && perr->perr_ttl > 1) { 1240 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, 1241 "propagate PERR from %6D", wh->i_addr2, ":"); 1242 memcpy(&pperr, perr, sizeof(*perr)); 1243 pperr.perr_ttl--; 1244 hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, 1245 &pperr); 1246 } 1247} 1248#undef PEER_DADDR 1249#undef PERR_DSEQ 1250 1251static int 1252hwmp_send_perr(struct ieee80211_node *ni, 1253 const uint8_t sa[IEEE80211_ADDR_LEN], 1254 const uint8_t da[IEEE80211_ADDR_LEN], 1255 struct ieee80211_meshperr_ie *perr) 1256{ 1257 struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp; 1258 1259 /* 1260 * Enforce PERR interval. 1261 */ 1262 if (ratecheck(&hs->hs_lastperr, &ieee80211_hwmp_perrminint) == 0) 1263 return EALREADY; 1264 getmicrouptime(&hs->hs_lastperr); 1265 1266 /* 1267 * mesh perr action frame format 1268 * [6] da 1269 * [6] sa 1270 * [6] addr3 = sa 1271 * [1] action 1272 * [1] category 1273 * [tlv] mesh path error 1274 */ 1275 perr->perr_ie = IEEE80211_ELEMID_MESHPERR; 1276 return hwmp_send_action(ni, sa, da, (uint8_t *)perr, 1277 sizeof(struct ieee80211_meshperr_ie)); 1278} 1279 1280static void 1281hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni, 1282 const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann) 1283{ 1284 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1285 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1286 struct ieee80211_mesh_route *rt = NULL; 1287 struct ieee80211_hwmp_route *hr; 1288 struct ieee80211_meshrann_ie prann; 1289 1290 if (ni == vap->iv_bss || 1291 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || 1292 IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr)) 1293 return; 1294 1295 rt = ieee80211_mesh_rt_find(vap, rann->rann_addr); 1296 /* 1297 * Discover the path to the root mesh STA. 1298 * If we already know it, propagate the RANN element. 1299 */ 1300 if (rt == NULL) { 1301 hwmp_discover(vap, rann->rann_addr, NULL); 1302 return; 1303 } 1304 hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); 1305 if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) { 1306 hr->hr_seq = rann->rann_seq; 1307 if (rann->rann_ttl > 1 && 1308 rann->rann_hopcount < hs->hs_maxhops && 1309 (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { 1310 memcpy(&prann, rann, sizeof(prann)); 1311 prann.rann_hopcount += 1; 1312 prann.rann_ttl -= 1; 1313 prann.rann_metric += ms->ms_pmetric->mpm_metric(ni); 1314 hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, 1315 broadcastaddr, &prann); 1316 } 1317 } 1318} 1319 1320static int 1321hwmp_send_rann(struct ieee80211_node *ni, 1322 const uint8_t sa[IEEE80211_ADDR_LEN], 1323 const uint8_t da[IEEE80211_ADDR_LEN], 1324 struct ieee80211_meshrann_ie *rann) 1325{ 1326 /* 1327 * mesh rann action frame format 1328 * [6] da 1329 * [6] sa 1330 * [6] addr3 = sa 1331 * [1] action 1332 * [1] category 1333 * [tlv] root annoucement 1334 */ 1335 rann->rann_ie = IEEE80211_ELEMID_MESHRANN; 1336 return hwmp_send_action(ni, sa, da, (uint8_t *)rann, 1337 sizeof(struct ieee80211_meshrann_ie)); 1338} 1339 1340#define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags 1341#define PREQ_TADDR(n) preq.preq_targets[n].target_addr 1342#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq 1343static struct ieee80211_node * 1344hwmp_discover(struct ieee80211vap *vap, 1345 const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m) 1346{ 1347 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1348 struct ieee80211_mesh_state *ms = vap->iv_mesh; 1349 struct ieee80211_mesh_route *rt = NULL; 1350 struct ieee80211_hwmp_route *hr; 1351 struct ieee80211_meshpreq_ie preq; 1352 struct ieee80211_node *ni; 1353 int sendpreq = 0; 1354 1355 KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, 1356 ("not a mesh vap, opmode %d", vap->iv_opmode)); 1357 1358 KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest), 1359 ("%s: discovering self!", __func__)); 1360 1361 ni = NULL; 1362 if (!IEEE80211_IS_MULTICAST(dest)) { 1363 rt = ieee80211_mesh_rt_find(vap, dest); 1364 if (rt == NULL) { 1365 rt = ieee80211_mesh_rt_add(vap, dest); 1366 if (rt == NULL) { 1367 IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, 1368 ni, "unable to add discovery path to %6D", 1369 dest, ":"); 1370 vap->iv_stats.is_mesh_rtaddfailed++; 1371 goto done; 1372 } 1373 } 1374 hr = IEEE80211_MESH_ROUTE_PRIV(rt, 1375 struct ieee80211_hwmp_route); 1376 if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { 1377 if (hr->hr_origseq == 0) 1378 hr->hr_origseq = ++hs->hs_seq; 1379 rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL; 1380 rt->rt_lifetime = 1381 ticks_to_msecs(ieee80211_hwmp_pathtimeout); 1382 /* XXX check preq retries */ 1383 sendpreq = 1; 1384 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, 1385 "start path discovery (src %s), target seq %u", 1386 m == NULL ? "<none>" : ether_sprintf( 1387 mtod(m, struct ether_header *)->ether_shost), 1388 hr->hr_seq); 1389 /* 1390 * Try to discover the path for this node. 1391 * Group addressed PREQ Case A 1392 */ 1393 preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; 1394 preq.preq_hopcount = 0; 1395 preq.preq_ttl = ms->ms_ttl; 1396 preq.preq_id = ++hs->hs_preqid; 1397 IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); 1398 preq.preq_origseq = hr->hr_origseq; 1399 preq.preq_lifetime = rt->rt_lifetime; 1400 preq.preq_metric = rt->rt_metric; 1401 preq.preq_tcount = 1; 1402 IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest); 1403 PREQ_TFLAGS(0) = 0; 1404 if (ieee80211_hwmp_targetonly) 1405 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO; 1406 if (ieee80211_hwmp_replyforward) 1407 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF; 1408 PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN; 1409 PREQ_TSEQ(0) = hr->hr_seq; 1410 /* XXX check return value */ 1411 hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, 1412 broadcastaddr, &preq); 1413 } 1414 if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) 1415 ni = ieee80211_find_txnode(vap, rt->rt_nexthop); 1416 } else { 1417 ni = ieee80211_find_txnode(vap, dest); 1418 /* NB: if null then we leak mbuf */ 1419 KASSERT(ni != NULL, ("leak mcast frame")); 1420 return ni; 1421 } 1422done: 1423 if (ni == NULL && m != NULL) { 1424 if (sendpreq) { 1425 struct ieee80211com *ic = vap->iv_ic; 1426 /* 1427 * Queue packet for transmit when path discovery 1428 * completes. If discovery never completes the 1429 * frame will be flushed by way of the aging timer. 1430 */ 1431 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, 1432 "%s", "queue frame until path found"); 1433 m->m_pkthdr.rcvif = (void *)(uintptr_t) 1434 ieee80211_mac_hash(ic, dest); 1435 /* XXX age chosen randomly */ 1436 ieee80211_ageq_append(&ic->ic_stageq, m, 1437 IEEE80211_INACT_WAIT); 1438 } else { 1439 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, 1440 dest, NULL, "%s", "no valid path to this node"); 1441 m_freem(m); 1442 } 1443 } 1444 return ni; 1445} 1446#undef PREQ_TFLAGS 1447#undef PREQ_TADDR 1448#undef PREQ_TSEQ 1449 1450static int 1451hwmp_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1452{ 1453 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1454 int error; 1455 1456 if (vap->iv_opmode != IEEE80211_M_MBSS) 1457 return ENOSYS; 1458 error = 0; 1459 switch (ireq->i_type) { 1460 case IEEE80211_IOC_HWMP_ROOTMODE: 1461 ireq->i_val = hs->hs_rootmode; 1462 break; 1463 case IEEE80211_IOC_HWMP_MAXHOPS: 1464 ireq->i_val = hs->hs_maxhops; 1465 break; 1466 default: 1467 return ENOSYS; 1468 } 1469 return error; 1470} 1471IEEE80211_IOCTL_GET(hwmp, hwmp_ioctl_get80211); 1472 1473static int 1474hwmp_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 1475{ 1476 struct ieee80211_hwmp_state *hs = vap->iv_hwmp; 1477 int error; 1478 1479 if (vap->iv_opmode != IEEE80211_M_MBSS) 1480 return ENOSYS; 1481 error = 0; 1482 switch (ireq->i_type) { 1483 case IEEE80211_IOC_HWMP_ROOTMODE: 1484 if (ireq->i_val < 0 || ireq->i_val > 3) 1485 return EINVAL; 1486 hs->hs_rootmode = ireq->i_val; 1487 hwmp_rootmode_setup(vap); 1488 break; 1489 case IEEE80211_IOC_HWMP_MAXHOPS: 1490 if (ireq->i_val <= 0 || ireq->i_val > 255) 1491 return EINVAL; 1492 hs->hs_maxhops = ireq->i_val; 1493 break; 1494 default: 1495 return ENOSYS; 1496 } 1497 return error; 1498} 1499IEEE80211_IOCTL_SET(hwmp, hwmp_ioctl_set80211); 1500