Index: projects/mesh11s/sys/net80211/ieee80211_mesh.c =================================================================== --- projects/mesh11s/sys/net80211/ieee80211_mesh.c (revision 191621) +++ projects/mesh11s/sys/net80211/ieee80211_mesh.c (revision 191622) @@ -1,636 +1,636 @@ /*- * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting * Copyright (c) 2009 The FreeBSD Foundation * All rights reserved. * * This software was developed by Rui Paulo under sponsorship from the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifdef __FreeBSD__ __FBSDID("$FreeBSD$"); #endif /* * IEEE 802.11s Mesh Point (MBSS) support. */ #include "opt_inet.h" #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void mesh_vattach(struct ieee80211vap *); static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int, uint32_t); static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, int, int, uint32_t); void ieee80211_mesh_attach(struct ieee80211com *ic) { ic->ic_vattach[IEEE80211_M_MBSS] = mesh_vattach; } void ieee80211_mesh_detach(struct ieee80211com *ic) { } static void mesh_vdetach(struct ieee80211vap *vap) { } static void mesh_vattach(struct ieee80211vap *vap) { vap->iv_newstate = mesh_newstate; vap->iv_input = mesh_input; vap->iv_opdetach = mesh_vdetach; vap->iv_recv_mgmt = mesh_recv_mgmt; } /* * IEEE80211_M_MBSS vap state machine handler. */ static int mesh_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; enum ieee80211_state ostate; IEEE80211_LOCK_ASSERT(ic); ostate = vap->iv_state; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg); vap->iv_state = nstate; /* state transition */ if (ostate != IEEE80211_S_SCAN) ieee80211_cancel_scan(vap); /* background scan */ ni = vap->iv_bss; /* NB: no reference held */ switch (nstate) { case IEEE80211_S_INIT: if (ostate == IEEE80211_S_SCAN) ieee80211_cancel_scan(vap); if (ostate != IEEE80211_S_INIT) { /* NB: optimize INIT -> INIT case */ ieee80211_reset_bss(vap); } break; case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_INIT: if (vap->iv_des_chan != IEEE80211_CHAN_ANYC && !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) { /* * Already have a channel; bypass the * scan and startup immediately. */ ieee80211_create_mbss(vap, vap->iv_des_chan); break; } /* * Initiate a scan. We can come here as a result * of an IEEE80211_IOC_SCAN_REQ too in which case * the vap will be marked with IEEE80211_FEXT_SCANREQ * and the scan request parameters will be present * in iv_scanreq. Otherwise we do the default. */ if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { ieee80211_check_scan(vap, vap->iv_scanreq_flags, vap->iv_scanreq_duration, vap->iv_scanreq_mindwell, vap->iv_scanreq_maxdwell, vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; } else ieee80211_check_scan_current(vap); break; default: break; } case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: case IEEE80211_S_CAC: case IEEE80211_S_RUN: case IEEE80211_S_CSA: case IEEE80211_S_SLEEP: default: break; } return 0; } /* * Decide if a received management frame should be * printed when debugging is enabled. This filters some * of the less interesting frames that come frequently * (e.g. beacons). */ static __inline int doprint(struct ieee80211vap *vap, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN); case IEEE80211_FC0_SUBTYPE_PROBE_REQ: return 1; } return 1; } static int mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int noise, uint32_t rstamp) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = vap->iv_ifp; struct ieee80211_frame *wh; int need_tap; uint8_t dir, type, subtype; KASSERT(ni != NULL, ("null node")); ni->ni_inact = ni->ni_inact_reload; need_tap = 1; /* mbuf need to be tapped. */ type = -1; /* undefined */ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, ni->ni_macaddr, NULL, "too short (1): len %u", m->m_pkthdr.len); vap->iv_stats.is_rx_tooshort++; goto out; } /* * Bit of a cheat here, we use a pointer for a 3-address * frame format but don't reference fields past outside * ieee80211_frame_min w/o first validating the data is * present. */ wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, ni->ni_macaddr, NULL, "wrong version %x", wh->i_fc[0]); vap->iv_stats.is_rx_badversion++; goto err; } dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { } switch (type) { case IEEE80211_FC0_TYPE_DATA: case IEEE80211_FC0_TYPE_MGT: vap->iv_stats.is_rx_mgmt++; IEEE80211_NODE_STAT(ni, rx_mgmt); if (dir != IEEE80211_FC1_DIR_NODS) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "data", "incorrect dir 0x%x", dir); vap->iv_stats.is_rx_wrongdir++; goto err; } if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, ni->ni_macaddr, "mgt", "too short: len %u", m->m_pkthdr.len); vap->iv_stats.is_rx_tooshort++; goto out; } #ifdef IEEE80211_DEBUG if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) || ieee80211_msg_dumppkts(vap)) { if_printf(ifp, "received %s from %s rssi %d\n", ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], ether_sprintf(wh->i_addr2), rssi); } #endif if (wh->i_fc[1] & IEEE80211_FC1_WEP) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "WEP set but not permitted"); vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ goto out; } if (bpf_peers_present(vap->iv_rawbpf)) bpf_mtap(vap->iv_rawbpf, m); vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp); m_freem(m); return IEEE80211_FC0_TYPE_MGT; case IEEE80211_FC0_TYPE_CTL: vap->iv_stats.is_rx_ctl++; IEEE80211_NODE_STAT(ni, rx_ctrl); goto out; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "bad", "frame type 0x%x", type); /* should not come here */ break; } err: ifp->if_ierrors++; out: if (m != NULL) { if (bpf_peers_present(vap->iv_rawbpf) && need_tap) bpf_mtap(vap->iv_rawbpf, m); m_freem(m); } return type; } static int is11bclient(const uint8_t *rates, const uint8_t *xrates) { static const uint32_t brates = (1<<2*1)|(1<<2*2)|(1<<11)|(1<<2*11); int i; /* NB: the 11b clients we care about will not have xrates */ if (xrates != NULL || rates == NULL) return 0; for (i = 0; i < rates[1]; i++) { int r = rates[2+i] & IEEE80211_RATE_VAL; if (r > 2*11 || ((1<ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; uint8_t *frm, *efrm; wh = mtod(m0, struct ieee80211_frame *); frm = (uint8_t *)&wh[1]; efrm = mtod(m0, uint8_t *) + m0->m_len; switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_BEACON: { struct ieee80211_scanparams scan; /* * We process beacon/probe response * frames to discover neighbors. */ if (ieee80211_parse_beacon(ni, m0, &scan) != 0) return; /* * Count frame now that we know it's to be processed. */ if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) { vap->iv_stats.is_rx_beacon++; /* XXX remove */ IEEE80211_NODE_STAT(ni, rx_beacons); } else IEEE80211_NODE_STAT(ni, rx_proberesp); /* * If scanning, just pass information to the scan module. */ if (ic->ic_flags & IEEE80211_F_SCAN) { if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) { /* * Actively scanning a channel marked passive; * send a probe request now that we know there * is 802.11 traffic present. * * XXX check if the beacon we recv'd gives * us what we need and suppress the probe req */ ieee80211_probe_curchan(vap, 1); ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; } ieee80211_add_scan(vap, &scan, wh, subtype, rssi, noise, rstamp); return; } break; } case IEEE80211_FC0_SUBTYPE_PROBE_REQ: { uint8_t *ssid, *meshid, *rates, *xrates; uint8_t *sfrm; if (vap->iv_state != IEEE80211_S_RUN) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "wrong state %s", ieee80211_state_name[vap->iv_state]); vap->iv_stats.is_rx_mgtdiscard++; return; } if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { /* frame must be directed */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "not unicast"); vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return; } /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] Mesh ID */ ssid = meshid = rates = xrates = NULL; sfrm = frm; while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); switch (*frm) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_MESHID: meshid = frm; break; } frm += frm[2] + 2; } IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return); IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return); if (xrates != NULL) IEEE80211_VERIFY_ELEMENT(xrates, IEEE80211_RATE_MAXSIZE - rates[1], return); if (meshid != NULL) IEEE80211_VERIFY_ELEMENT(meshid, IEEE80211_MESHID_LEN, return); IEEE80211_VERIFY_SSID(vap->iv_bss, ssid, return); /* XXX add verify meshid ? */ /* XXX find a better class or define it's own */ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2, "%s", "recv probe req"); /* * Some legacy 11b clients cannot hack a complete * probe response frame. When the request includes * only a bare-bones rate set, communicate this to * the transmit side. */ ieee80211_send_proberesp(vap, wh->i_addr2, is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0); break; } case IEEE80211_FC0_SUBTYPE_ACTION: break; case IEEE80211_FC0_SUBTYPE_AUTH: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: case IEEE80211_FC0_SUBTYPE_DEAUTH: case IEEE80211_FC0_SUBTYPE_DISASSOC: IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; return; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } } /* * Parse a MESH ID ie on station join. */ void ieee80211_parse_meshid(struct ieee80211_node *ni, const uint8_t *ie) { struct ieee80211vap *vap = ni->ni_vap; if (vap->iv_caps & IEEE80211_C_MBSS) { /*const struct ieee80211_meshid_ie *meshid = (const struct ieee80211_meshid_ie *)ie;*/ /* * Mesh STAs are QoS stations, so QoS is not optional. */ ni->ni_flags |= IEEE80211_NODE_QOS; } } /* * Add a MESH ID element to a frame. */ uint8_t * ieee80211_add_meshid(uint8_t *frm, struct ieee80211vap *vap) { KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a mbss vap")); *frm++ = IEEE80211_ELEMID_MESHID; *frm++ = vap->iv_meshidlen; memcpy(frm, vap->iv_meshid, vap->iv_meshidlen); return frm + vap->iv_meshidlen; } /* * Add a Mesh Configuration element to a frame. * For now just use HWMP routing, Airtime link metric, Null Congestion * Signaling, Null Sync Protocol and Null Authentication. */ uint8_t * ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap) { static const struct ieee80211_meshconf_ie ie = { .conf_ie = IEEE80211_ELEMID_MESHCONF, .conf_len = sizeof(struct ieee80211_meshconf_ie) - 2, .conf_ver = IEEE80211_MESHCONF_VERSION, .conf_pselid = IEEE80211_MESHCONF_HWMP, .conf_pmetid = IEEE80211_MESHCONF_AIRTIME, - .conf_ccid = IEEE80211_MESHCONF_NULL, - .conf_syncid = IEEE80211_MESHCONF_NULL, - .conf_authid = IEEE80211_MESHCONF_NULL, + .conf_ccid = IEEE80211_MESHCONF_CCSIG, + .conf_syncid = { 0, 0, 0, 0 }, /* XXX */ + .conf_authid = { 0x80, 0, 0, 0 }, /* XXX */ .conf_form = 0, /* XXX */ .conf_cap = 1, /* XXX */ }; KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a mbss vap")); memcpy(frm, &ie, sizeof(ie)); return frm + sizeof(ie); } void ieee80211_create_mbss(struct ieee80211vap *vap, struct ieee80211_channel *chan) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: creating mbss on channel %u\n", __func__, ieee80211_chan2ieee(ic, chan)); ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); if (ni == NULL) { /* XXX recovery? */ return; } IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr); ni->ni_meshidlen = vap->iv_meshidlen; memcpy(ni->ni_meshid, vap->iv_meshid, ni->ni_meshidlen); ni->ni_intval = ic->ic_bintval; /* * Fix the channel and related attributes. */ /* clear DFS CAC state on previous channel */ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && ic->ic_bsschan->ic_freq != chan->ic_freq && IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) ieee80211_dfs_cac_clear(ic, ic->ic_bsschan); ic->ic_bsschan = chan; ieee80211_node_set_chan(ni, chan); ic->ic_curmode = ieee80211_chan2mode(chan); /* * Do mode-specific setup. */ if (IEEE80211_IS_CHAN_FULL(chan)) { if (IEEE80211_IS_CHAN_ANYG(chan)) { /* * Use a mixed 11b/11g basic rate set. */ ieee80211_setbasicrates(&ni->ni_rates, IEEE80211_MODE_11G); if (vap->iv_flags & IEEE80211_F_PUREG) { /* * Also mark OFDM rates basic so 11b * stations do not join (WiFi compliance). */ ieee80211_addbasicrates(&ni->ni_rates, IEEE80211_MODE_11A); } } else if (IEEE80211_IS_CHAN_B(chan)) { /* * Force pure 11b rate set. */ ieee80211_setbasicrates(&ni->ni_rates, IEEE80211_MODE_11B); } } ieee80211_ref_node(ni); vap->iv_bss = ni; ieee80211_setcurchan(ic, ni->ni_chan); /* * Set the erp state (mostly the slot time) to deal with * the auto-select case; this should be redundant if the * mode is locked. */ ieee80211_reset_erp(ic); ieee80211_wme_initparams(vap); ieee80211_new_state(vap, IEEE80211_S_RUN, -1); } static int mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) { int error; uint8_t tmpmeshid[IEEE80211_NWID_LEN]; error = 0; switch (ireq->i_type) { case IEEE80211_IOC_MESH_ID: if (vap->iv_opmode != IEEE80211_M_MBSS) return EINVAL; ireq->i_len = vap->iv_meshidlen; memcpy(tmpmeshid, vap->iv_meshid, ireq->i_len); error = copyout(tmpmeshid, ireq->i_data, ireq->i_len); break; default: return ENOSYS; } return error; } IEEE80211_IOCTL_GET(mesh, mesh_ioctl_get80211); static int mesh_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) { int error; uint8_t tmpmeshid[IEEE80211_NWID_LEN]; error = 0; switch (ireq->i_type) { case IEEE80211_IOC_MESH_ID: if (ireq->i_val != 0 || ireq->i_len > IEEE80211_NWID_LEN) return EINVAL; error = copyin(ireq->i_data, tmpmeshid, ireq->i_len); if (error) break; memset(vap->iv_meshid, 0, IEEE80211_NWID_LEN); vap->iv_meshidlen = ireq->i_len; memcpy(vap->iv_meshid, tmpmeshid, ireq->i_len); break; default: return ENOSYS; } return error; } IEEE80211_IOCTL_SET(mesh, mesh_ioctl_set80211); Index: projects/mesh11s/sys/net80211/ieee80211_mesh.h =================================================================== --- projects/mesh11s/sys/net80211/ieee80211_mesh.h (revision 191621) +++ projects/mesh11s/sys/net80211/ieee80211_mesh.h (revision 191622) @@ -1,313 +1,320 @@ /*- * Copyright (c) 2009 The FreeBSD Foundation * All rights reserved. * * This software was developed by Rui Paulo under sponsorship from the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _NET80211_IEEE80211_MESH_H_ #define _NET80211_IEEE80211_MESH_H_ /* * 802.11s Information Elements. */ /* Mesh Configuration */ struct ieee80211_meshconf_ie { uint8_t conf_ie; /* IEEE80211_ELEMID_MESHCONF */ uint8_t conf_len; uint8_t conf_ver; - uint32_t conf_pselid; /* Active Path Sel. Proto. ID */ - uint32_t conf_pmetid; /* APS Metric Identifier */ - uint32_t conf_ccid; /* Congestion Control Mode ID */ - uint32_t conf_syncid; /* Sync. Protocol ID */ - uint32_t conf_authid; /* Auth. Protocol ID */ + uint8_t conf_pselid[4]; /* Active Path Sel. Proto. ID */ + uint8_t conf_pmetid[4]; /* APS Metric Identifier */ + uint8_t conf_ccid[4]; /* Congestion Control Mode ID */ + uint8_t conf_syncid[4]; /* Sync. Protocol ID */ + uint8_t conf_authid[4]; /* Auth. Protocol ID */ uint8_t conf_form; /* Formation Information */ uint8_t conf_cap; } __packed; #define IEEE80211_MESHCONF_VERSION 1 -#define IEEE80211_MESHCONF_NULL_OUI 0x000fac /* Null Protocol */ -#define IEEE80211_MESHCONF_NULL_VALUE 255 -#define IEEE80211_MESHCONF_NULL (IEEE80211_MESHCONF_NULL_OUI << 8 | IEEE80211_MESHCONF_NULL_VALUE) -#define IEEE80211_MESHCONF_HWMP_OUI 0x000fac +/* Null Protocol */ +#define IEEE80211_MESHCONF_NULL_OUI 0x00, 0x0f, 0xac +#define IEEE80211_MESHCONF_NULL_VALUE 0xff +#define IEEE80211_MESHCONF_NULL { IEEE80211_MESHCONF_NULL_OUI, IEEE80211_MESHCONF_NULL_VALUE } +/* Hybrid Wireless Mesh Protocol */ +#define IEEE80211_MESHCONF_HWMP_OUI 0x00, 0x0f, 0xac #define IEEE80211_MESHCONF_HWMP_VALUE 0xff /* XXX Linux */ -#define IEEE80211_MESHCONF_HWMP (IEEE80211_MESHCONF_HWMP_OUI << 8 | IEEE80211_MESHCONF_HWMP_VALUE) -#define IEEE80211_MESHCONF_AIRTIME_OUI 0x000fac +#define IEEE80211_MESHCONF_HWMP { IEEE80211_MESHCONF_HWMP_OUI, IEEE80211_MESHCONF_HWMP_VALUE } +/* Airtime Link Metric */ +#define IEEE80211_MESHCONF_AIRTIME_OUI 0x00, 0x0f, 0xac #define IEEE80211_MESHCONF_AIRTIME_VALUE 0xff /* XXX Linux */ -#define IEEE80211_MESHCONF_AIRTIME (IEEE80211_MESHCONF_AIRTIME_OUI << 8 | IEEE80211_MESHCONF_AIRTIME_VALUE) -#define IEEE80211_MESHCONF_CCSIG_OUI 0x000fac +#define IEEE80211_MESHCONF_AIRTIME { IEEE80211_MESHCONF_AIRTIME_OUI, IEEE80211_MESHCONF_AIRTIME_VALUE } +/* Congestion Control Signaling */ +#define IEEE80211_MESHCONF_CCSIG_OUI 0x00, 0x0f, 0xac #define IEEE80211_MESHCONF_CCSIG_VALUE 0xff /* XXX Linux */ -#define IEEE80211_MESHCONF_NEIGHOFF_OUI 0x000fac /* Neighbour offset */ -#define IEEE80211_MESHCONF_NEIGHOFF_VALUE 0 -#define IEEE80211_MESHCONF_NEIGHOFF (IEEE80211_MESHCONF_NEIGHOFF_OUI << 8 | IEEE80211_MESHCONF_NEIGHOFF_VALUE) -#define IEEE80211_MESHCONF_SAE_OUI 0x000fac -#define IEEE80211_MESHCONF_SAE_VALUE 1 -#define IEEE80211_MESHCONF_SAE (IEEE80211_MESHCONF_SAE_OUI << 8 | IEEE80211_MESHCONF_SAE_VALUE) +#define IEEE80211_MESHCONF_CCSIG { IEEE80211_MESHCONF_CCSIG_OUI, IEEE80211_MESHCONF_CCSIG_VALUE } +/* Neighbour Offset */ +#define IEEE80211_MESHCONF_NEIGHOFF_OUI 0x00, 0x0f, 0xac +#define IEEE80211_MESHCONF_NEIGHOFF_VALUE 0x00 +#define IEEE80211_MESHCONF_NEIGHOFF { IEEE80211_MESHCONF_NEIGHOFF_OUI, IEEE80211_MESHCONF_NEIGHOFF_VALUE } +/* Simultaneous Authenticaction of Equals */ +#define IEEE80211_MESHCONF_SAE_OUI 0x00, 0x0f, 0xac +#define IEEE80211_MESHCONF_SAE_VALUE 0x01 +#define IEEE80211_MESHCONF_SAE { IEEE80211_MESHCONF_SAE_OUI, IEEE80211_MESHCONF_SAE_VALUE } #define IEEE80211_MESHCONF_FORM_MP (1 << 1) /* connected to portal */ #define IEEE80211_MESHCONF_FORM_NEIGH (1 << 4) /* no of neighbours */ /* XXX ... */ /* Mesh Identifier */ struct ieee80211_meshid_ie { uint8_t id_ie; /* IEEE80211_ELEMID_MESHID */ uint8_t id_len; } __packed; #define IEEE80211_MESHID_LEN IEEE80211_NWID_LEN /* Link Metric Report */ struct ieee80211_meshlink_ie { uint8_t link_ie; /* IEEE80211_ELEMID_MESHLINK */ uint8_t link_len; /* XXXRP: missing variable metric */ } __packed; /* Congestion Notification */ struct ieee80211_meshcngst_ie { uint8_t cngst_ie; /* IEEE80211_ELEMID_MESHCNGST */ uint8_t cngst_len; uint16_t cngst_timer[4]; /* Expiration Timers: AC_BK, AC_BE, AC_VI, AC_VO */ } __packed; /* Peer Link Management */ struct ieee80211_meshpeer_ie { uint8_t peer_ie; /* IEEE80211_ELEMID_MESHPEER */ uint8_t peer_len; uint8_t peer_subtype; uint16_t peer_llinkid; /* Local Link ID */ uint16_t peer_linkid; /* Peer Link ID */ uint16_t peer_rcode; } __packed; enum { IEEE80211_MESH_PEER_LINK_OPEN = 0, IEEE80211_MESH_PEER_LINK_CONFIRM = 1, IEEE80211_MESH_PEER_LINK_CLOSE = 2, /* values 3-255 are reserved */ }; /* Mesh Channel Switch Annoucement */ struct ieee80211_meshcsa_ie { uint8_t csa_ie; /* IEEE80211_ELEMID_MESHCSA */ uint8_t csa_len; uint8_t csa_mode; uint8_t csa_newclass; /* New Regulatory Class */ uint8_t csa_newchan; uint8_t csa_precvalue; /* Precedence Value */ uint8_t csa_count; } __packed; /* XXXRP: this is equal to the non mesh version. Should we simplify ? */ /* Mesh TIM */ struct ieee80211_meshtim_ie { uint8_t tim_ie; /* IEEE80211_ELEMID_MESHTIM */ uint8_t tim_len; uint8_t tim_count; /* DTIM count */ uint8_t tim_period; /* DTIM period */ uint8_t tim_bitctl; /* bitmap control */ uint8_t tim_bitmap[1]; /* variable-length bitmap */ } __packed; /* Mesh Awake Window */ struct ieee80211_meshawakew_ie { uint8_t awakew_ie; /* IEEE80211_ELEMID_MESHAWAKEW */ uint8_t awakew_len; uint8_t awakew_windowlen; /* in TUs */ } __packed; /* Mesh Beacon Timing */ struct ieee80211_meshbeacont_ie { uint8_t beacont_ie; /* IEEE80211_ELEMID_MESHBEACONT */ uint8_t beacont_len; struct { uint8_t mp_aid; /* Least Octet of AID */ uint16_t mp_btime; /* Beacon Time */ uint16_t mp_bint; /* Beacon Interval */ } mp[1] __packed; /* NB: variable size */ } __packed; /* Mesh Timing Info */ struct ieee80211_meshtinfo_ie { uint8_t tinfo_ie; /* IEEE80211_ELEMID_MESHTIMINGINFO */ uint8_t tinfo_len; uint8_t tinfo_field; } __packed; #define IEEE80211_MESH_TINFO_BEACON_PARAMS_CHANGED (1 << 8) #define IEEE80211_MESH_TINFO_MDA_ENABLED (1 << 7) /* Synchronization Protocol */ struct ieee80211_meshsyncproto_ie { uint8_t syncproto_ie; /* IEEE80211_ELEMID_MESHSYNCPROTO */ uint8_t syncproto_len; uint32_t syncproto_id; /* Sync Protocol ID OUI */ } __packed; /* Neighbour Offset Protocol */ #define IEEE80211_MESH_SYNCPROTO_NEIGHOFFSET_OUI 0x000fac #define IEEE80211_MESH_SYNCPROTO_NEIGHOFFSET_VALUE 0 /* MDAOP Setup Request */ struct ieee80211_meshdaopsreq_ie { uint8_t daopsreq_ie; /* IEEE80211_ELEMID_MESHDAOPSREQ */ uint8_t daopsreq_len; uint8_t daopsreq_setid; uint32_t daposreq_reserv; /* MDAOP Reservation */ } __packed; /* MDAOP Setup Reply */ struct ieee80211_meshdaopsrep_ie { uint8_t daopsrep_ie; /* IEEE80211_ELEMID_MESHDAOPSREPLY */ uint8_t daopsrep_len; uint8_t daopsrep_setid; uint8_t daopsrep_code; /* Reply Code */ uint8_t daopsrep_reserv; /* MDAOP Reservation */ } __packed; enum { IEEE80211_MESH_DAOP_REPLY_ACCEPT = 0, IEEE80211_MESH_DAOP_REPLY_RESERV_CONFLICT = 1, IEEE80211_MESH_DAOP_REPLY_MAF_LIMIT = 2, /* everything else is reserved */ }; /* MDAOP Advertisements */ /* TBD */ /* MDAOP Set Teardown */ struct ieee80211_meshdaopst_ie { uint8_t daopsrep_ie; /* IEEE80211_ELEMID_MESHDAOPSREP */ uint8_t daopsrep_len; uint8_t daopsrep_setid; uint8_t daopsrep_setowner[IEEE80211_ADDR_LEN]; } __packed; /* Portal (MP) Annoucement */ struct ieee80211_meshpann_ie { uint8_t pann_ie; /* IEEE80211_ELEMID_MESHPANN */ uint8_t pann_len; uint8_t pann_flags; uint8_t pann_hopcount; uint8_t pann_ttl; uint8_t pann_addr[IEEE80211_ADDR_LEN]; uint8_t pann_seq; /* PANN Sequence Number */ } __packed; /* Root (MP) Annoucement */ struct ieee80211_meshrann_ie { uint8_t rann_ie; /* IEEE80211_ELEMID_MESHRANN */ uint8_t rann_len; uint8_t rann_flags; uint8_t rann_hopcount; uint8_t rann_ttl; uint8_t rann_addr[IEEE80211_ADDR_LEN]; uint32_t rann_seq; /* HWMP Sequence Number */ uint32_t rann_metric; } __packed; /* Mesh Path Request */ struct ieee80211_meshpreq_ie { uint8_t preq_ie; /* IEEE80211_ELEMID_MESHPREQ */ uint8_t preq_len; /* XXXRP: TBD */ } __packed; /* Mesh Path Reply */ struct ieee80211_meshprep_ie { uint8_t prep_ie; /* IEEE80211_ELEMID_MESHPREP */ uint8_t prep_len; /* XXXRP: TBD */ } __packed; /* Mesh Path Error */ struct ieee80211_meshperr_ie { uint8_t perr_ie; /* IEEE80211_ELEMID_MESHPERR */ uint8_t perr_len; uint8_t perr_mode; uint8_t perr_ndests; /* Number of Destinations */ struct { uint8_t dest_addr[IEEE80211_ADDR_LEN]; uint32_t dest_seq; } dests[1] __packed; /* NB: variable size */ } __packed; /* Mesh Proxy Update */ struct ieee80211_meshpu_ie { uint8_t pu_ie; /* IEEE80211_ELEMID_MESHPU */ uint8_t pu_len; /* XXXRP: TBD */ } __packed; /* Mesh Proxy Update Confirmation */ struct ieee80211_meshpuc_ie { uint8_t puc_ie; /* IEEE80211_ELEMID_MESHPUC */ uint8_t puc_len; uint8_t puc_flags; uint8_t puc_seq; /* PU Sequence Number */ uint8_t puc_daddr[IEEE80211_ADDR_LEN]; } __packed; /* Mesh Security Capability */ struct ieee80211_meshsc_ie { uint8_t sc_ie; /* IEEE80211_ELEMID_MESHSC */ uint8_t sc_len; uint8_t sc_mkdid[IEEE80211_ADDR_LEN]; /* MKD Domain ID */ uint8_t sc_sconfig; /* Security Configuration */ } __packed; /* Mesh Security Authentication */ struct ieee80211_meshsa_ie { uint8_t sa_ie; /* IEEE80211_ELEMID_MESHSA */ uint8_t sa_len; uint8_t sa_handshake; uint8_t sa_maid[IEEE80211_ADDR_LEN]; /* MA-ID */ uint8_t sa_lmpid[IEEE80211_ADDR_LEN]; uint32_t sa_akm; /* Selected AKM Suite */ uint32_t sa_pcs; /* Selected Pairwise Cipher Suite */ uint8_t sa_pmk[16]; uint8_t sa_lnonce[32]; uint8_t sa_pnonce[32]; /* XXX more parameters */ } __packed; /* Mesh Anti-Clogging Token */ struct ieee80211_meshact_ie { uint8_t act_ie; /* IEEE80211_ELEMID_MESHACT */ uint8_t act_len; } __packed; void ieee80211_mesh_attach(struct ieee80211com *); void ieee80211_mesh_detach(struct ieee80211com *); void ieee80211_parse_meshid(struct ieee80211_node *, const uint8_t *); uint8_t * ieee80211_add_meshid(uint8_t *, struct ieee80211vap *); uint8_t * ieee80211_add_meshconf(uint8_t *, struct ieee80211vap *); void ieee80211_create_mbss(struct ieee80211vap *, struct ieee80211_channel *); #endif /* !_NET80211_IEEE80211_MESH_H_ */