[Midnightbsd-cvs] src [9937] trunk/sys/net80211: sync with freebsd 10-stable
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Fri May 25 16:04:32 EDT 2018
Revision: 9937
http://svnweb.midnightbsd.org/src/?rev=9937
Author: laffer1
Date: 2018-05-25 16:04:31 -0400 (Fri, 25 May 2018)
Log Message:
-----------
sync with freebsd 10-stable
Modified Paths:
--------------
trunk/sys/net80211/_ieee80211.h
trunk/sys/net80211/ieee80211.c
trunk/sys/net80211/ieee80211.h
trunk/sys/net80211/ieee80211_acl.c
trunk/sys/net80211/ieee80211_action.c
trunk/sys/net80211/ieee80211_action.h
trunk/sys/net80211/ieee80211_adhoc.c
trunk/sys/net80211/ieee80211_adhoc.h
trunk/sys/net80211/ieee80211_ageq.c
trunk/sys/net80211/ieee80211_ageq.h
trunk/sys/net80211/ieee80211_alq.c
trunk/sys/net80211/ieee80211_alq.h
trunk/sys/net80211/ieee80211_amrr.c
trunk/sys/net80211/ieee80211_amrr.h
trunk/sys/net80211/ieee80211_crypto.c
trunk/sys/net80211/ieee80211_crypto.h
trunk/sys/net80211/ieee80211_crypto_ccmp.c
trunk/sys/net80211/ieee80211_crypto_none.c
trunk/sys/net80211/ieee80211_crypto_tkip.c
trunk/sys/net80211/ieee80211_crypto_wep.c
trunk/sys/net80211/ieee80211_ddb.c
trunk/sys/net80211/ieee80211_dfs.c
trunk/sys/net80211/ieee80211_dfs.h
trunk/sys/net80211/ieee80211_freebsd.c
trunk/sys/net80211/ieee80211_freebsd.h
trunk/sys/net80211/ieee80211_hostap.c
trunk/sys/net80211/ieee80211_hostap.h
trunk/sys/net80211/ieee80211_ht.c
trunk/sys/net80211/ieee80211_ht.h
trunk/sys/net80211/ieee80211_hwmp.c
trunk/sys/net80211/ieee80211_input.c
trunk/sys/net80211/ieee80211_input.h
trunk/sys/net80211/ieee80211_ioctl.c
trunk/sys/net80211/ieee80211_ioctl.h
trunk/sys/net80211/ieee80211_mesh.c
trunk/sys/net80211/ieee80211_mesh.h
trunk/sys/net80211/ieee80211_monitor.c
trunk/sys/net80211/ieee80211_monitor.h
trunk/sys/net80211/ieee80211_node.c
trunk/sys/net80211/ieee80211_node.h
trunk/sys/net80211/ieee80211_output.c
trunk/sys/net80211/ieee80211_phy.c
trunk/sys/net80211/ieee80211_phy.h
trunk/sys/net80211/ieee80211_power.c
trunk/sys/net80211/ieee80211_power.h
trunk/sys/net80211/ieee80211_proto.c
trunk/sys/net80211/ieee80211_proto.h
trunk/sys/net80211/ieee80211_radiotap.c
trunk/sys/net80211/ieee80211_radiotap.h
trunk/sys/net80211/ieee80211_ratectl.c
trunk/sys/net80211/ieee80211_ratectl.h
trunk/sys/net80211/ieee80211_ratectl_none.c
trunk/sys/net80211/ieee80211_regdomain.c
trunk/sys/net80211/ieee80211_regdomain.h
trunk/sys/net80211/ieee80211_rssadapt.c
trunk/sys/net80211/ieee80211_rssadapt.h
trunk/sys/net80211/ieee80211_scan.c
trunk/sys/net80211/ieee80211_scan.h
trunk/sys/net80211/ieee80211_scan_sta.c
trunk/sys/net80211/ieee80211_sta.c
trunk/sys/net80211/ieee80211_sta.h
trunk/sys/net80211/ieee80211_superg.c
trunk/sys/net80211/ieee80211_superg.h
trunk/sys/net80211/ieee80211_tdma.c
trunk/sys/net80211/ieee80211_tdma.h
trunk/sys/net80211/ieee80211_var.h
trunk/sys/net80211/ieee80211_wds.c
trunk/sys/net80211/ieee80211_wds.h
trunk/sys/net80211/ieee80211_xauth.c
Modified: trunk/sys/net80211/_ieee80211.h
===================================================================
--- trunk/sys/net80211/_ieee80211.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/_ieee80211.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/_ieee80211.h 237871 2012-07-01 04:25:49Z adrian $
*/
#ifndef _NET80211__IEEE80211_H_
#define _NET80211__IEEE80211_H_
@@ -242,6 +243,8 @@
(((_c)->ic_flags & (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)) != 0)
#define IEEE80211_IS_CHAN_CCK(_c) \
(((_c)->ic_flags & (IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN)) != 0)
+#define IEEE80211_IS_CHAN_DYN(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_DYN) == IEEE80211_CHAN_DYN)
#define IEEE80211_IS_CHAN_GFSK(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0)
#define IEEE80211_IS_CHAN_TURBO(_c) \
Modified: trunk/sys/net80211/ieee80211.c
===================================================================
--- trunk/sys/net80211/ieee80211.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211.c 254315 2013-08-14 04:24:25Z rpaulo $");
/*
* IEEE 802.11 generic handler
@@ -241,9 +242,15 @@
return EACCES; /* XXX EIO/EPERM? */
}
+#if __FreeBSD_version >= 1000031
static int
null_output(struct ifnet *ifp, struct mbuf *m,
+ const struct sockaddr *dst, struct route *ro)
+#else
+static int
+null_output(struct ifnet *ifp, struct mbuf *m,
struct sockaddr *dst, struct route *ro)
+#endif
{
if_printf(ifp, "discard raw packet\n");
return null_transmit(ifp, m);
@@ -256,6 +263,13 @@
m_freem(m);
}
+static void
+null_update_chw(struct ieee80211com *ic)
+{
+
+ if_printf(ic->ic_ifp, "%s: need callback\n", __func__);
+}
+
/*
* Attach/setup the common net80211 state. Called by
* the driver on attach to prior to creating any vap's.
@@ -271,12 +285,13 @@
KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type));
IEEE80211_LOCK_INIT(ic, ifp->if_xname);
+ IEEE80211_TX_LOCK_INIT(ic, ifp->if_xname);
TAILQ_INIT(&ic->ic_vaps);
/* Create a taskqueue for all state changes */
ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO,
taskqueue_thread_enqueue, &ic->ic_tq);
- taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s taskq",
+ taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq",
ifp->if_xname);
/*
* Fill in 802.11 available channel set, mark all
@@ -287,6 +302,7 @@
ic->ic_update_mcast = null_update_mcast;
ic->ic_update_promisc = null_update_promisc;
+ ic->ic_update_chw = null_update_chw;
ic->ic_hash_key = arc4random();
ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
@@ -309,7 +325,11 @@
ifp->if_addrlen = IEEE80211_ADDR_LEN;
ifp->if_hdrlen = 0;
+
+ CURVNET_SET(vnet0);
+
if_attach(ifp);
+
ifp->if_mtu = IEEE80211_MTU_MAX;
ifp->if_broadcastaddr = ieee80211broadcastaddr;
ifp->if_output = null_output;
@@ -323,6 +343,8 @@
sdl->sdl_alen = IEEE80211_ADDR_LEN;
IEEE80211_ADDR_COPY(LLADDR(sdl), macaddr);
ifa_free(ifa);
+
+ CURVNET_RESTORE();
}
/*
@@ -337,8 +359,18 @@
struct ifnet *ifp = ic->ic_ifp;
struct ieee80211vap *vap;
+ /*
+ * This detaches the main interface, but not the vaps.
+ * Each VAP may be in a separate VIMAGE.
+ */
+ CURVNET_SET(ifp->if_vnet);
if_detach(ifp);
+ CURVNET_RESTORE();
+ /*
+ * The VAP is responsible for setting and clearing
+ * the VIMAGE context.
+ */
while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
ieee80211_vap_destroy(vap);
ieee80211_waitfor_parent(ic);
@@ -357,8 +389,11 @@
ieee80211_power_detach(ic);
ieee80211_node_detach(ic);
+ /* XXX VNET needed? */
ifmedia_removeall(&ic->ic_media);
+
taskqueue_free(ic->ic_tq);
+ IEEE80211_TX_LOCK_DESTROY(ic);
IEEE80211_LOCK_DESTROY(ic);
}
@@ -399,13 +434,10 @@
if_initname(ifp, name, unit);
ifp->if_softc = vap; /* back pointer */
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
- ifp->if_start = ieee80211_start;
+ ifp->if_transmit = ieee80211_vap_transmit;
+ ifp->if_qflush = ieee80211_vap_qflush;
ifp->if_ioctl = ieee80211_ioctl;
ifp->if_init = ieee80211_init;
- /* NB: input+output filled in by ether_ifattach */
- IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
- ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
- IFQ_SET_READY(&ifp->if_snd);
vap->iv_ifp = ifp;
vap->iv_ic = ic;
@@ -578,6 +610,8 @@
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = vap->iv_ifp;
+ CURVNET_SET(ifp->if_vnet);
+
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n",
__func__, ieee80211_opmode_name[vap->iv_opmode],
ic->ic_ifp->if_xname);
@@ -630,6 +664,8 @@
ieee80211_sysctl_vdetach(vap);
if_free(ifp);
+
+ CURVNET_RESTORE();
}
/*
@@ -1483,7 +1519,6 @@
int
ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
static const struct ratemedia rates[] = {
{ 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
{ 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
@@ -1604,7 +1639,7 @@
if (mode == IEEE80211_MODE_11NA) {
if (rate & IEEE80211_RATE_MCS) {
rate &= ~IEEE80211_RATE_MCS;
- m = findmedia(htrates, N(htrates), rate);
+ m = findmedia(htrates, nitems(htrates), rate);
if (m != IFM_AUTO)
return m | IFM_IEEE80211_11NA;
}
@@ -1612,7 +1647,7 @@
/* NB: 12 is ambiguous, it will be treated as an MCS */
if (rate & IEEE80211_RATE_MCS) {
rate &= ~IEEE80211_RATE_MCS;
- m = findmedia(htrates, N(htrates), rate);
+ m = findmedia(htrates, nitems(htrates), rate);
if (m != IFM_AUTO)
return m | IFM_IEEE80211_11NG;
}
@@ -1625,15 +1660,18 @@
case IEEE80211_MODE_11NA:
case IEEE80211_MODE_TURBO_A:
case IEEE80211_MODE_STURBO_A:
- return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A);
+ return findmedia(rates, nitems(rates),
+ rate | IFM_IEEE80211_11A);
case IEEE80211_MODE_11B:
- return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B);
+ return findmedia(rates, nitems(rates),
+ rate | IFM_IEEE80211_11B);
case IEEE80211_MODE_FH:
- return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH);
+ return findmedia(rates, nitems(rates),
+ rate | IFM_IEEE80211_FH);
case IEEE80211_MODE_AUTO:
/* NB: ic may be NULL for some drivers */
if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH)
- return findmedia(rates, N(rates),
+ return findmedia(rates, nitems(rates),
rate | IFM_IEEE80211_FH);
/* NB: hack, 11g matches both 11b+11a rates */
/* fall thru... */
@@ -1640,16 +1678,14 @@
case IEEE80211_MODE_11G:
case IEEE80211_MODE_11NG:
case IEEE80211_MODE_TURBO_G:
- return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G);
+ return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11G);
}
return IFM_AUTO;
-#undef N
}
int
ieee80211_media2rate(int mword)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
static const int ieeerates[] = {
-1, /* IFM_AUTO */
0, /* IFM_MANUAL */
@@ -1677,9 +1713,8 @@
54, /* IFM_IEEE80211_OFDM27 */
-1, /* IFM_IEEE80211_MCS */
};
- return IFM_SUBTYPE(mword) < N(ieeerates) ?
+ return IFM_SUBTYPE(mword) < nitems(ieeerates) ?
ieeerates[IFM_SUBTYPE(mword)] : 0;
-#undef N
}
/*
Modified: trunk/sys/net80211/ieee80211.h
===================================================================
--- trunk/sys/net80211/ieee80211.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211.h 262007 2014-02-17 01:36:53Z kevlo $
*/
#ifndef _NET80211_IEEE80211_H_
#define _NET80211_IEEE80211_H_
@@ -166,7 +167,7 @@
#define IEEE80211_FC1_RETRY 0x08
#define IEEE80211_FC1_PWR_MGT 0x10
#define IEEE80211_FC1_MORE_DATA 0x20
-#define IEEE80211_FC1_WEP 0x40
+#define IEEE80211_FC1_PROTECTED 0x40
#define IEEE80211_FC1_ORDER 0x80
#define IEEE80211_SEQ_FRAG_MASK 0x000f
@@ -199,6 +200,13 @@
#define IEEE80211_QOS_EOSP 0x10 /* EndOfService Period*/
#define IEEE80211_QOS_EOSP_S 4
#define IEEE80211_QOS_TID 0x0f
+/* qos[1] byte used for all frames sent by mesh STAs in a mesh BSS */
+#define IEEE80211_QOS_MC 0x01 /* Mesh control */
+/* Mesh power save level*/
+#define IEEE80211_QOS_MESH_PSL 0x02
+/* Mesh Receiver Service Period Initiated */
+#define IEEE80211_QOS_RSPI 0x04
+/* bits 11 to 15 reserved */
/* does frame have QoS sequence control data */
#define IEEE80211_QOS_HAS_SEQ(wh) \
@@ -325,6 +333,9 @@
#define IEEE80211_ACTION_CAT_DLS 2 /* DLS */
#define IEEE80211_ACTION_CAT_BA 3 /* BA */
#define IEEE80211_ACTION_CAT_HT 7 /* HT */
+#define IEEE80211_ACTION_CAT_MESH 13 /* Mesh */
+#define IEEE80211_ACTION_CAT_SELF_PROT 15 /* Self-protected */
+/* 16 - 125 reserved */
#define IEEE80211_ACTION_CAT_VENDOR 127 /* Vendor Specific */
#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended xmit chan width*/
@@ -701,6 +712,7 @@
IEEE80211_ELEMID_IBSSDFS = 41,
IEEE80211_ELEMID_ERP = 42,
IEEE80211_ELEMID_HTCAP = 45,
+ IEEE80211_ELEMID_QOS = 46,
IEEE80211_ELEMID_RSN = 48,
IEEE80211_ELEMID_XRATES = 50,
IEEE80211_ELEMID_HTINFO = 61,
@@ -724,7 +736,7 @@
IEEE80211_ELEMID_MESHAWAKEW = 119,
IEEE80211_ELEMID_MESHBEACONT = 120,
/* 121-124 MMCAOP not implemented yet */
- IEEE80211_ELEMID_MESHPANN = 125, /* XXX: is GANN now, not used */
+ IEEE80211_ELEMID_MESHGANN = 125,
IEEE80211_ELEMID_MESHRANN = 126,
/* 127 Extended Capabilities */
/* 128-129 reserved */
@@ -762,6 +774,18 @@
(sizeof(struct ieee80211_country_ie) + 3*(IEEE80211_COUNTRY_MAX_BANDS-1))
/*
+ * 802.11h Quiet Time Element.
+ */
+struct ieee80211_quiet_ie {
+ uint8_t quiet_ie; /* IEEE80211_ELEMID_QUIET */
+ uint8_t len;
+ uint8_t tbttcount; /* quiet start */
+ uint8_t period; /* beacon intervals between quiets */
+ uint16_t duration; /* TUs of each quiet*/
+ uint16_t offset; /* TUs of from TBTT of quiet start */
+} __packed;
+
+/*
* 802.11h Channel Switch Announcement (CSA).
*/
struct ieee80211_csa_ie {
@@ -920,19 +944,21 @@
IEEE80211_REASON_SETUP_NEEDED = 38, /* 11e */
IEEE80211_REASON_TIMEOUT = 39, /* 11e */
- /* values not yet allocated by ANA */
- IEEE80211_REASON_PEER_LINK_CANCELED = 2, /* 11s */
- IEEE80211_REASON_MESH_MAX_PEERS = 3, /* 11s */
- IEEE80211_REASON_MESH_CPVIOLATION = 4, /* 11s */
- IEEE80211_REASON_MESH_CLOSE_RCVD = 5, /* 11s */
- IEEE80211_REASON_MESH_MAX_RETRIES = 6, /* 11s */
- IEEE80211_REASON_MESH_CONFIRM_TIMEOUT = 7, /* 11s */
- IEEE80211_REASON_MESH_INVALID_GTK = 8, /* 11s */
- IEEE80211_REASON_MESH_INCONS_PARAMS = 9, /* 11s */
- IEEE80211_REASON_MESH_INVALID_SECURITY = 10, /* 11s */
- IEEE80211_REASON_MESH_PERR_UNSPEC = 11, /* 11s */
- IEEE80211_REASON_MESH_PERR_NO_FI = 12, /* 11s */
- IEEE80211_REASON_MESH_PERR_DEST_UNREACH = 13, /* 11s */
+ IEEE80211_REASON_PEER_LINK_CANCELED = 52, /* 11s */
+ IEEE80211_REASON_MESH_MAX_PEERS = 53, /* 11s */
+ IEEE80211_REASON_MESH_CPVIOLATION = 54, /* 11s */
+ IEEE80211_REASON_MESH_CLOSE_RCVD = 55, /* 11s */
+ IEEE80211_REASON_MESH_MAX_RETRIES = 56, /* 11s */
+ IEEE80211_REASON_MESH_CONFIRM_TIMEOUT = 57, /* 11s */
+ IEEE80211_REASON_MESH_INVALID_GTK = 58, /* 11s */
+ IEEE80211_REASON_MESH_INCONS_PARAMS = 59, /* 11s */
+ IEEE80211_REASON_MESH_INVALID_SECURITY = 60, /* 11s */
+ IEEE80211_REASON_MESH_PERR_NO_PROXY = 61, /* 11s */
+ IEEE80211_REASON_MESH_PERR_NO_FI = 62, /* 11s */
+ IEEE80211_REASON_MESH_PERR_DEST_UNREACH = 63, /* 11s */
+ IEEE80211_REASON_MESH_MAC_ALRDY_EXISTS_MBSS = 64, /* 11s */
+ IEEE80211_REASON_MESH_CHAN_SWITCH_REG = 65, /* 11s */
+ IEEE80211_REASON_MESH_CHAN_SWITCH_UNSPEC = 66, /* 11s */
IEEE80211_STATUS_SUCCESS = 0,
IEEE80211_STATUS_UNSPECIFIED = 1,
Modified: trunk/sys/net80211/ieee80211_acl.c
===================================================================
--- trunk/sys/net80211/ieee80211_acl.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_acl.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD: src/sys/net80211/ieee80211_acl.c,v 1.6 2013/01/17 23:29:37 laffer1 Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_acl.c 228622 2011-12-17 10:32:31Z bschmidt $");
/*
* IEEE 802.11 MAC ACL support.
@@ -152,7 +153,7 @@
}
static int
-acl_check(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
+acl_check(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
{
struct aclstate *as = vap->iv_as;
@@ -161,9 +162,9 @@
case ACL_POLICY_RADIUS:
return 1;
case ACL_POLICY_ALLOW:
- return _find_acl(as, mac) != NULL;
+ return _find_acl(as, wh->i_addr2) != NULL;
case ACL_POLICY_DENY:
- return _find_acl(as, mac) == NULL;
+ return _find_acl(as, wh->i_addr2) == NULL;
}
return 0; /* should not happen */
}
Modified: trunk/sys/net80211/ieee80211_action.c
===================================================================
--- trunk/sys/net80211/ieee80211_action.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_action.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_action.c 254315 2013-08-14 04:24:25Z rpaulo $");
#endif
/*
@@ -67,10 +68,8 @@
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
};
-static ieee80211_send_action_func *meshlm_send_action[4] = {
+static ieee80211_send_action_func *meshaction_send_action[12] = {
send_inval, send_inval, send_inval, send_inval,
-};
-static ieee80211_send_action_func *hwmp_send_action[8] = {
send_inval, send_inval, send_inval, send_inval,
send_inval, send_inval, send_inval, send_inval,
};
@@ -82,41 +81,35 @@
int
ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
switch (cat) {
case IEEE80211_ACTION_CAT_BA:
- if (act >= N(ba_send_action))
+ if (act >= nitems(ba_send_action))
break;
ba_send_action[act] = f;
return 0;
case IEEE80211_ACTION_CAT_HT:
- if (act >= N(ht_send_action))
+ if (act >= nitems(ht_send_action))
break;
ht_send_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHPEERING:
- if (act >= N(meshpl_send_action))
+ case IEEE80211_ACTION_CAT_SELF_PROT:
+ if (act >= nitems(meshpl_send_action))
break;
meshpl_send_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHLMETRIC:
- if (act >= N(meshlm_send_action))
+ case IEEE80211_ACTION_CAT_MESH:
+ if (act >= nitems(meshaction_send_action))
break;
- meshlm_send_action[act] = f;
+ meshaction_send_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHPATH:
- if (act >= N(hwmp_send_action))
- break;
- hwmp_send_action[act] = f;
- return 0;
+ break;
case IEEE80211_ACTION_CAT_VENDOR:
- if (act >= N(vendor_send_action))
+ if (act >= nitems(vendor_send_action))
break;
vendor_send_action[act] = f;
return 0;
}
return EINVAL;
-#undef N
}
void
@@ -128,37 +121,31 @@
int
ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
ieee80211_send_action_func *f = send_inval;
switch (cat) {
case IEEE80211_ACTION_CAT_BA:
- if (act < N(ba_send_action))
+ if (act < nitems(ba_send_action))
f = ba_send_action[act];
break;
case IEEE80211_ACTION_CAT_HT:
- if (act < N(ht_send_action))
+ if (act < nitems(ht_send_action))
f = ht_send_action[act];
break;
- case IEEE80211_ACTION_CAT_MESHPEERING:
- if (act < N(meshpl_send_action))
+ case IEEE80211_ACTION_CAT_SELF_PROT:
+ if (act < nitems(meshpl_send_action))
f = meshpl_send_action[act];
break;
- case IEEE80211_ACTION_CAT_MESHLMETRIC:
- if (act < N(meshlm_send_action))
- f = meshlm_send_action[act];
+ case IEEE80211_ACTION_CAT_MESH:
+ if (act < nitems(meshaction_send_action))
+ f = meshaction_send_action[act];
break;
- case IEEE80211_ACTION_CAT_MESHPATH:
- if (act < N(hwmp_send_action))
- f = hwmp_send_action[act];
- break;
case IEEE80211_ACTION_CAT_VENDOR:
- if (act < N(vendor_send_action))
+ if (act < nitems(vendor_send_action))
f = vendor_send_action[act];
break;
}
return f(ni, cat, act, sa);
-#undef N
}
static int
@@ -180,10 +167,8 @@
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
};
-static ieee80211_recv_action_func *meshlm_recv_action[4] = {
+static ieee80211_recv_action_func *meshaction_recv_action[12] = {
recv_inval, recv_inval, recv_inval, recv_inval,
-};
-static ieee80211_recv_action_func *hwmp_recv_action[8] = {
recv_inval, recv_inval, recv_inval, recv_inval,
recv_inval, recv_inval, recv_inval, recv_inval,
};
@@ -195,41 +180,34 @@
int
ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
switch (cat) {
case IEEE80211_ACTION_CAT_BA:
- if (act >= N(ba_recv_action))
+ if (act >= nitems(ba_recv_action))
break;
ba_recv_action[act] = f;
return 0;
case IEEE80211_ACTION_CAT_HT:
- if (act >= N(ht_recv_action))
+ if (act >= nitems(ht_recv_action))
break;
ht_recv_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHPEERING:
- if (act >= N(meshpl_recv_action))
+ case IEEE80211_ACTION_CAT_SELF_PROT:
+ if (act >= nitems(meshpl_recv_action))
break;
meshpl_recv_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHLMETRIC:
- if (act >= N(meshlm_recv_action))
+ case IEEE80211_ACTION_CAT_MESH:
+ if (act >= nitems(meshaction_recv_action))
break;
- meshlm_recv_action[act] = f;
+ meshaction_recv_action[act] = f;
return 0;
- case IEEE80211_ACTION_CAT_MESHPATH:
- if (act >= N(hwmp_recv_action))
- break;
- hwmp_recv_action[act] = f;
- return 0;
case IEEE80211_ACTION_CAT_VENDOR:
- if (act >= N(vendor_recv_action))
+ if (act >= nitems(vendor_recv_action))
break;
vendor_recv_action[act] = f;
return 0;
}
return EINVAL;
-#undef N
}
void
@@ -243,37 +221,41 @@
const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
ieee80211_recv_action_func *f = recv_inval;
+ struct ieee80211vap *vap = ni->ni_vap;
const struct ieee80211_action *ia =
(const struct ieee80211_action *) frm;
switch (ia->ia_category) {
case IEEE80211_ACTION_CAT_BA:
- if (ia->ia_action < N(ba_recv_action))
+ if (ia->ia_action < nitems(ba_recv_action))
f = ba_recv_action[ia->ia_action];
break;
case IEEE80211_ACTION_CAT_HT:
- if (ia->ia_action < N(ht_recv_action))
+ if (ia->ia_action < nitems(ht_recv_action))
f = ht_recv_action[ia->ia_action];
break;
- case IEEE80211_ACTION_CAT_MESHPEERING:
- if (ia->ia_action < N(meshpl_recv_action))
+ case IEEE80211_ACTION_CAT_SELF_PROT:
+ if (ia->ia_action < nitems(meshpl_recv_action))
f = meshpl_recv_action[ia->ia_action];
break;
- case IEEE80211_ACTION_CAT_MESHLMETRIC:
- if (ia->ia_action < N(meshlm_recv_action))
- f = meshlm_recv_action[ia->ia_action];
+ case IEEE80211_ACTION_CAT_MESH:
+ if (ni == vap->iv_bss ||
+ ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
+ ni->ni_macaddr, NULL,
+ "peer link not yet established (%d), cat %s act %u",
+ ni->ni_mlstate, "mesh action", ia->ia_action);
+ vap->iv_stats.is_mesh_nolink++;
+ break;
+ }
+ if (ia->ia_action < nitems(meshaction_recv_action))
+ f = meshaction_recv_action[ia->ia_action];
break;
- case IEEE80211_ACTION_CAT_MESHPATH:
- if (ia->ia_action < N(hwmp_recv_action))
- f = hwmp_recv_action[ia->ia_action];
- break;
case IEEE80211_ACTION_CAT_VENDOR:
- if (ia->ia_action < N(vendor_recv_action))
+ if (ia->ia_action < nitems(vendor_recv_action))
f = vendor_recv_action[ia->ia_action];
break;
}
return f(ni, wh, frm, efrm);
-#undef N
}
Modified: trunk/sys/net80211/ieee80211_action.h
===================================================================
--- trunk/sys/net80211/ieee80211_action.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_action.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_action.h 195377 2009-07-05 17:59:19Z sam $
*/
#ifndef _NET80211_IEEE80211_ACTION_H_
#define _NET80211_IEEE80211_ACTION_H_
Modified: trunk/sys/net80211/ieee80211_adhoc.c
===================================================================
--- trunk/sys/net80211/ieee80211_adhoc.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_adhoc.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_adhoc.c 262007 2014-02-17 01:36:53Z kevlo $");
#endif
/*
@@ -63,6 +64,7 @@
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
+#include <net80211/ieee80211_sta.h>
#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
@@ -170,7 +172,9 @@
* Already have a channel; bypass the
* scan and startup immediately.
*/
- ieee80211_create_ibss(vap, vap->iv_des_chan);
+ ieee80211_create_ibss(vap,
+ ieee80211_ht_adjust_channel(ic,
+ vap->iv_des_chan, vap->iv_flags_ht));
break;
}
/*
@@ -242,7 +246,7 @@
ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN);
break;
case IEEE80211_S_SLEEP:
- ieee80211_sta_pwrsave(vap, 0);
+ vap->iv_sta_ps(vap, 0);
break;
default:
invalid:
@@ -471,7 +475,7 @@
* crypto cipher modules used to do delayed update
* of replay sequence numbers.
*/
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
/*
* Discard encrypted frames when privacy is off.
@@ -489,7 +493,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
} else {
/* XXX M_WEP and IEEE80211_F_PRIVACY */
key = NULL;
@@ -627,7 +631,7 @@
ether_sprintf(wh->i_addr2), rssi);
}
#endif
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, NULL, "%s", "WEP set but not permitted");
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
@@ -685,6 +689,9 @@
struct ieee80211_frame *wh;
uint8_t *frm, *efrm, *sfrm;
uint8_t *ssid, *rates, *xrates;
+#if 0
+ int ht_state_change = 0;
+#endif
wh = mtod(m0, struct ieee80211_frame *);
frm = (uint8_t *)&wh[1];
@@ -745,10 +752,42 @@
memcpy(ni->ni_tstamp.data, scan.tstamp,
sizeof(ni->ni_tstamp));
}
+ /*
+ * This isn't enabled yet - otherwise it would
+ * update the HT parameters and channel width
+ * from any node, which could lead to lots of
+ * strange behaviour if the 11n nodes aren't
+ * exactly configured to match.
+ */
+#if 0
+ if (scan.htcap != NULL && scan.htinfo != NULL &&
+ (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
+ if (ieee80211_ht_updateparams(ni,
+ scan.htcap, scan.htinfo))
+ ht_state_change = 1;
+ }
+#endif
if (ni != NULL) {
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
}
+ /*
+ * Same here - the channel width change should
+ * be applied to the specific peer node, not
+ * to the ic. Ie, the interface configuration
+ * should stay in its current channel width;
+ * but it should change the rate control and
+ * any queued frames for the given node only.
+ *
+ * Since there's no (current) way to inform
+ * the driver that a channel width change has
+ * occured for a single node, just stub this
+ * out.
+ */
+#if 0
+ if (ht_state_change)
+ ieee80211_update_chw(ic);
+#endif
}
break;
}
Modified: trunk/sys/net80211/ieee80211_adhoc.h
===================================================================
--- trunk/sys/net80211/ieee80211_adhoc.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_adhoc.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_adhoc.h 178354 2008-04-20 20:35:46Z sam $
*/
#ifndef _NET80211_IEEE80211_ADHOC_H_
#define _NET80211_IEEE80211_ADHOC_H_
Modified: trunk/sys/net80211/ieee80211_ageq.c
===================================================================
--- trunk/sys/net80211/ieee80211_ageq.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ageq.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ageq.c 223842 2011-07-07 15:41:40Z kevlo $");
/*
* IEEE 802.11 age queue support.
Modified: trunk/sys/net80211/ieee80211_ageq.h
===================================================================
--- trunk/sys/net80211/ieee80211_ageq.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ageq.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_ageq.h 195379 2009-07-05 18:17:37Z sam $
*/
#ifndef _NET80211_IEEE80211_STAGEQ_H_
#define _NET80211_IEEE80211_STAGEQ_H_
Modified: trunk/sys/net80211/ieee80211_alq.c
===================================================================
--- trunk/sys/net80211/ieee80211_alq.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_alq.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_alq.c 233255 2012-03-21 03:19:50Z adrian $");
#endif
/*
@@ -85,8 +86,10 @@
ieee80211_alq_qsize);
ieee80211_alq_lost = 0;
ieee80211_alq_logged = 0;
- printf("net80211: logging to %s enabled; struct size %d bytes\n",
- ieee80211_alq_logfile, sizeof(struct ieee80211_alq_rec));
+ printf("net80211: logging to %s enabled; "
+ "struct size %d bytes\n",
+ ieee80211_alq_logfile,
+ sizeof(struct ieee80211_alq_rec));
} else {
if (ieee80211_alq)
alq_close(ieee80211_alq);
@@ -100,14 +103,14 @@
static int
sysctl_ieee80211_alq_log(SYSCTL_HANDLER_ARGS)
{
- int error, enable;
+ int error, enable;
- enable = (ieee80211_alq != NULL);
- error = sysctl_handle_int(oidp, &enable, 0, req);
- if (error || !req->newptr)
- return (error);
- else
- return (ieee80211_alq_setlogging(enable));
+ enable = (ieee80211_alq != NULL);
+ error = sysctl_handle_int(oidp, &enable, 0, req);
+ if (error || !req->newptr)
+ return (error);
+ else
+ return (ieee80211_alq_setlogging(enable));
}
SYSCTL_PROC(_net_wlan, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
@@ -150,6 +153,7 @@
r->r_version = 1;
r->r_wlan = htons(vap->iv_ifp->if_dunit);
r->r_op = op;
+ r->r_threadid = htonl((uint32_t) curthread->td_tid);
memcpy(&r->r_payload, p, MIN(l, sizeof(r->r_payload)));
alq_post(ieee80211_alq, ale);
}
Modified: trunk/sys/net80211/ieee80211_alq.h
===================================================================
--- trunk/sys/net80211/ieee80211_alq.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_alq.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_alq.h 233133 2012-03-18 21:54:59Z adrian $
*/
#ifndef __IEEE80211_ALQ_H__
#define __IEEE80211_ALQ_H__
@@ -38,6 +39,7 @@
*/
struct ieee80211_alq_rec {
uint32_t r_timestamp; /* XXX may wrap! */
+ uint32_t r_threadid; /* current thread id */
uint16_t r_wlan; /* wlan interface number */
uint8_t r_version; /* version */
uint8_t r_op; /* top-level operation id */
@@ -46,6 +48,7 @@
};
/* General logging function */
-extern void ieee80211_alq_log(struct ieee80211vap *vap, uint8_t op, u_char *p, int l);
+extern void ieee80211_alq_log(struct ieee80211vap *vap, uint8_t op,
+ u_char *p, int l);
#endif /* __IEEE80211_ALQ_H__ */
Modified: trunk/sys/net80211/ieee80211_amrr.c
===================================================================
--- trunk/sys/net80211/ieee80211_amrr.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_amrr.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/* $OpenBSD: ieee80211_amrr.c,v 1.1 2006/06/17 19:07:19 damien Exp $ */
/*-
@@ -19,7 +20,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_amrr.c 321725 2017-07-30 18:38:05Z avos $");
/*-
* Naive implementation of the Adaptive Multi Rate Retry algorithm:
@@ -46,6 +47,7 @@
#endif
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_ht.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
@@ -110,6 +112,7 @@
KASSERT(vap->iv_rs == NULL, ("%s called multiple times", __func__));
+ nrefs++; /* XXX locking */
amrr = vap->iv_rs = malloc(sizeof(struct ieee80211_amrr),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (amrr == NULL) {
@@ -126,15 +129,29 @@
amrr_deinit(struct ieee80211vap *vap)
{
free(vap->iv_rs, M_80211_RATECTL);
+ KASSERT(nrefs > 0, ("imbalanced attach/detach"));
+ nrefs--; /* XXX locking */
}
+static int
+amrr_node_is_11n(struct ieee80211_node *ni)
+{
+
+ if (ni->ni_chan == NULL)
+ return (0);
+ if (ni->ni_chan == IEEE80211_CHAN_ANYC)
+ return (0);
+ return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
+}
+
static void
amrr_node_init(struct ieee80211_node *ni)
{
- const struct ieee80211_rateset *rs = &ni->ni_rates;
+ const struct ieee80211_rateset *rs = NULL;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_amrr *amrr = vap->iv_rs;
struct ieee80211_amrr_node *amn;
+ uint8_t rate;
if (ni->ni_rctls == NULL) {
ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
@@ -152,16 +169,50 @@
amn->amn_txcnt = amn->amn_retrycnt = 0;
amn->amn_success_threshold = amrr->amrr_min_success_threshold;
- /* pick initial rate */
- for (amn->amn_rix = rs->rs_nrates - 1;
- amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
- amn->amn_rix--)
- ;
- ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: 11n node", __func__);
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: non-11n node", __func__);
+ rs = &ni->ni_rates;
+ }
+
+ /* Initial rate - lowest */
+ rate = rs->rs_rates[0];
+
+ /* XXX clear the basic rate flag if it's not 11n */
+ if (! amrr_node_is_11n(ni))
+ rate &= IEEE80211_RATE_VAL;
+
+ /* pick initial rate from the rateset - HT or otherwise */
+ for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
+ amn->amn_rix--) {
+ /* legacy - anything < 36mbit, stop searching */
+ /* 11n - stop at MCS4 / MCS12 / MCS28 */
+ if (amrr_node_is_11n(ni) &&
+ (rs->rs_rates[amn->amn_rix] & 0x7) < 4)
+ break;
+ else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
+ break;
+ rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ }
+
+ /* if the rate is an 11n rate, ensure the MCS bit is set */
+ if (amrr_node_is_11n(ni))
+ rate |= IEEE80211_RATE_MCS;
+
+ /* Assign initial rate from the rateset */
+ ni->ni_txrate = rate;
amn->amn_ticks = ticks;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
- "AMRR initial rate %d", ni->ni_txrate);
+ "AMRR: nrates=%d, initial rate %d",
+ rs->rs_nrates,
+ rate);
}
static void
@@ -175,19 +226,42 @@
struct ieee80211_node *ni)
{
int rix = amn->amn_rix;
+ const struct ieee80211_rateset *rs = NULL;
KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
+ amn->amn_txcnt,
+ amn->amn_retrycnt);
+
+ /*
+ * XXX This is totally bogus for 11n, as although high MCS
+ * rates for each stream may be failing, the next stream
+ * should be checked.
+ *
+ * Eg, if MCS5 is ok but MCS6/7 isn't, and we can go up to
+ * MCS23, we should skip 6/7 and try 8 onwards.
+ */
if (is_success(amn)) {
amn->amn_success++;
if (amn->amn_success >= amn->amn_success_threshold &&
- rix + 1 < ni->ni_rates.rs_nrates) {
+ rix + 1 < rs->rs_nrates) {
amn->amn_recovery = 1;
amn->amn_success = 0;
rix++;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
} else {
amn->amn_recovery = 0;
@@ -208,7 +282,7 @@
rix--;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
}
amn->amn_recovery = 0;
@@ -231,14 +305,27 @@
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
struct ieee80211_amrr *amrr = amn->amn_amrr;
+ const struct ieee80211_rateset *rs = NULL;
int rix;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
rix = amrr_update(amrr, amn, ni);
if (rix != amn->amn_rix) {
/* update public rate */
- ni->ni_txrate =
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
+ ni->ni_txrate = rs->rs_rates[rix];
+ /* XXX strip basic rate flag from txrate, if non-11n */
+ if (amrr_node_is_11n(ni))
+ ni->ni_txrate |= IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate &= IEEE80211_RATE_VAL;
amn->amn_rix = rix;
}
amn->amn_ticks = ticks;
Modified: trunk/sys/net80211/ieee80211_amrr.h
===================================================================
--- trunk/sys/net80211/ieee80211_amrr.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_amrr.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,4 +1,5 @@
/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/net80211/ieee80211_amrr.h 206358 2010-04-07 15:29:13Z rpaulo $ */
/* $OpenBSD: ieee80211_amrr.h,v 1.3 2006/06/17 19:34:31 damien Exp $ */
/*-
Modified: trunk/sys/net80211/ieee80211_crypto.c
===================================================================
--- trunk/sys/net80211/ieee80211_crypto.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_crypto.c 195812 2009-07-21 19:36:32Z sam $");
/*
* IEEE 802.11 generic crypto support.
Modified: trunk/sys/net80211/ieee80211_crypto.h
===================================================================
--- trunk/sys/net80211/ieee80211_crypto.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_crypto.h 209636 2010-07-01 20:50:12Z bschmidt $
*/
#ifndef _NET80211_IEEE80211_CRYPTO_H_
#define _NET80211_IEEE80211_CRYPTO_H_
Modified: trunk/sys/net80211/ieee80211_crypto_ccmp.c
===================================================================
--- trunk/sys/net80211/ieee80211_crypto_ccmp.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto_ccmp.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_crypto_ccmp.c 209636 2010-07-01 20:50:12Z bschmidt $");
/*
* IEEE 802.11i AES-CCMP crypto support.
Modified: trunk/sys/net80211/ieee80211_crypto_none.c
===================================================================
--- trunk/sys/net80211/ieee80211_crypto_none.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto_none.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_crypto_none.c 178354 2008-04-20 20:35:46Z sam $");
/*
* IEEE 802.11 NULL crypto support.
Modified: trunk/sys/net80211/ieee80211_crypto_tkip.c
===================================================================
--- trunk/sys/net80211/ieee80211_crypto_tkip.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto_tkip.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_crypto_tkip.c 209636 2010-07-01 20:50:12Z bschmidt $");
/*
* IEEE 802.11i TKIP crypto support.
Modified: trunk/sys/net80211/ieee80211_crypto_wep.c
===================================================================
--- trunk/sys/net80211/ieee80211_crypto_wep.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_crypto_wep.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_crypto_wep.c 305615 2016-09-08 15:06:28Z pfg $");
/*
* IEEE 802.11 WEP crypto support.
@@ -419,7 +420,7 @@
}
off = hdrlen + wep.ic_header;
- data_len = m->m_pkthdr.len - (off + wep.ic_trailer),
+ data_len = m->m_pkthdr.len - (off + wep.ic_trailer);
/* Compute CRC32 over unencrypted data and apply RC4 to data */
crc = ~0;
Modified: trunk/sys/net80211/ieee80211_ddb.c
===================================================================
--- trunk/sys/net80211/ieee80211_ddb.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ddb.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ddb.c 246516 2013-02-07 21:29:48Z monthadar $");
#include "opt_ddb.h"
#include "opt_wlan.h"
@@ -63,9 +64,9 @@
} while (0)
static void _db_show_sta(const struct ieee80211_node *);
-static void _db_show_vap(const struct ieee80211vap *, int);
+static void _db_show_vap(const struct ieee80211vap *, int, int);
static void _db_show_com(const struct ieee80211com *,
- int showvaps, int showsta, int showprocs);
+ int showvaps, int showsta, int showmesh, int showprocs);
static void _db_show_node_table(const char *tag,
const struct ieee80211_node_table *);
@@ -103,7 +104,7 @@
DB_SHOW_COMMAND(vap, db_show_vap)
{
- int i, showprocs = 0;
+ int i, showmesh = 0, showprocs = 0;
if (!have_addr) {
db_printf("usage: show vap <addr>\n");
@@ -113,18 +114,22 @@
switch (modif[i]) {
case 'a':
showprocs = 1;
+ showmesh = 1;
break;
+ case 'm':
+ showmesh = 1;
+ break;
case 'p':
showprocs = 1;
break;
}
- _db_show_vap((const struct ieee80211vap *) addr, showprocs);
+ _db_show_vap((const struct ieee80211vap *) addr, showmesh, showprocs);
}
DB_SHOW_COMMAND(com, db_show_com)
{
const struct ieee80211com *ic;
- int i, showprocs = 0, showvaps = 0, showsta = 0;
+ int i, showprocs = 0, showvaps = 0, showsta = 0, showmesh = 0;
if (!have_addr) {
db_printf("usage: show com <addr>\n");
@@ -133,11 +138,14 @@
for (i = 0; modif[i] != '\0'; i++)
switch (modif[i]) {
case 'a':
- showsta = showvaps = showprocs = 1;
+ showsta = showmesh = showvaps = showprocs = 1;
break;
case 's':
showsta = 1;
break;
+ case 'm':
+ showmesh = 1;
+ break;
case 'v':
showvaps = 1;
break;
@@ -147,7 +155,7 @@
}
ic = (const struct ieee80211com *) addr;
- _db_show_com(ic, showvaps, showsta, showprocs);
+ _db_show_com(ic, showvaps, showsta, showmesh, showprocs);
}
DB_SHOW_ALL_COMMAND(vaps, db_show_all_vaps)
@@ -178,7 +186,7 @@
vap->iv_ifp->if_xname, vap);
db_printf("\n");
} else
- _db_show_com(ic, 1, 1, 1);
+ _db_show_com(ic, 1, 1, 1, 1);
}
}
}
@@ -202,7 +210,7 @@
{
db_printf("%stxampdu[%d]: %p flags %b %s\n",
sep, ix, tap, tap->txa_flags, IEEE80211_AGGR_BITS,
- ieee80211_wme_acnames[tap->txa_ac]);
+ ieee80211_wme_acnames[TID_TO_WME_AC(tap->txa_tid)]);
db_printf("%s token %u lastsample %d pkts %d avgpps %d qbytes %d qframes %d\n",
sep, tap->txa_token, tap->txa_lastsample, tap->txa_pkts,
tap->txa_avgpps, tap->txa_qbytes, tap->txa_qframes);
@@ -293,7 +301,7 @@
ni->ni_htopmode, ni->ni_htstbc, ni->ni_chw);
/* XXX ampdu state */
- for (i = 0; i < WME_NUM_AC; i++)
+ for (i = 0; i < WME_NUM_TID; i++)
if (ni->ni_tx_ampdu[i].txa_flags & IEEE80211_AGGR_SETUP)
_db_show_txampdu("\t", i, &ni->ni_tx_ampdu[i]);
for (i = 0; i < WME_NUM_TID; i++)
@@ -330,7 +338,7 @@
#endif /* IEEE80211_SUPPORT_TDMA */
static void
-_db_show_vap(const struct ieee80211vap *vap, int showprocs)
+_db_show_vap(const struct ieee80211vap *vap, int showmesh, int showprocs)
{
const struct ieee80211com *ic = vap->iv_ic;
int i;
@@ -341,6 +349,10 @@
db_printf("\n");
db_printf("\topmode %s", ieee80211_opmode_name[vap->iv_opmode]);
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode == IEEE80211_M_MBSS)
+ db_printf("(%p)", vap->iv_mesh);
+#endif
db_printf(" state %s", ieee80211_state_name[vap->iv_state]);
db_printf(" ifp %p(%s)", vap->iv_ifp, vap->iv_ifp->if_xname);
db_printf("\n");
@@ -472,6 +484,10 @@
db_printf(" acl %p", vap->iv_acl);
db_printf(" as %p", vap->iv_as);
db_printf("\n");
+#ifdef IEEE80211_SUPPORT_MESH
+ if (showmesh && vap->iv_mesh != NULL)
+ _db_show_mesh(vap->iv_mesh);
+#endif
#ifdef IEEE80211_SUPPORT_TDMA
if (vap->iv_tdma != NULL)
_db_show_tdma("\t", vap->iv_tdma, showprocs);
@@ -495,7 +511,8 @@
}
static void
-_db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, int showprocs)
+_db_show_com(const struct ieee80211com *ic, int showvaps, int showsta,
+ int showmesh, int showprocs)
{
struct ieee80211vap *vap;
@@ -651,7 +668,7 @@
if (showvaps && !TAILQ_EMPTY(&ic->ic_vaps)) {
db_printf("\n");
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
- _db_show_vap(vap, showprocs);
+ _db_show_vap(vap, showmesh, showprocs);
}
if (showsta && !TAILQ_EMPTY(&ic->ic_sta.nt_node)) {
const struct ieee80211_node_table *nt = &ic->ic_sta;
@@ -870,8 +887,10 @@
TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
db_printf("entry %d:\tdest: %6D nexthop: %6D metric: %u", i,
rt->rt_dest, ":", rt->rt_nexthop, ":", rt->rt_metric);
+
db_printf("\tlifetime: %u lastseq: %u priv: %p\n",
- rt->rt_lifetime, rt->rt_lastmseq, rt->rt_priv);
+ ieee80211_mesh_rt_update(rt, 0),
+ rt->rt_lastmseq, rt->rt_priv);
i++;
}
}
Modified: trunk/sys/net80211/ieee80211_dfs.c
===================================================================
--- trunk/sys/net80211/ieee80211_dfs.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_dfs.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD: src/sys/net80211/ieee80211_dfs.c,v 1.2 2013/01/17 23:29:38 laffer1 Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_dfs.c 230793 2012-01-31 00:03:49Z adrian $");
#endif
/*
@@ -64,6 +65,34 @@
&ieee80211_cac_timeout, 0, "CAC timeout (secs)");
#define CAC_TIMEOUT msecs_to_ticks(ieee80211_cac_timeout*1000)
+/*
+ DFS* In order to facilitate debugging, a couple of operating
+ * modes aside from the default are needed.
+ *
+ * 0 - default CAC/NOL behaviour - ie, start CAC, place
+ * channel on NOL list.
+ * 1 - send CAC, but don't change channel or add the channel
+ * to the NOL list.
+ * 2 - just match on radar, don't send CAC or place channel in
+ * the NOL list.
+ */
+static int ieee80211_dfs_debug = DFS_DBG_NONE;
+
+/*
+ * This option must not be included in the default kernel
+ * as it allows users to plainly disable CAC/NOL handling.
+ */
+#ifdef IEEE80211_DFS_DEBUG
+SYSCTL_INT(_net_wlan, OID_AUTO, dfs_debug, CTLFLAG_RW,
+ &ieee80211_dfs_debug, 0, "DFS debug behaviour");
+#endif
+
+static int
+null_set_quiet(struct ieee80211_node *ni, u_int8_t *quiet_elm)
+{
+ return ENOSYS;
+}
+
void
ieee80211_dfs_attach(struct ieee80211com *ic)
{
@@ -71,6 +100,8 @@
callout_init_mtx(&dfs->nol_timer, IEEE80211_LOCK_OBJ(ic), 0);
callout_init_mtx(&dfs->cac_timer, IEEE80211_LOCK_OBJ(ic), 0);
+
+ ic->ic_set_quiet = null_set_quiet;
}
void
@@ -270,24 +301,44 @@
IEEE80211_LOCK_ASSERT(ic);
/*
- * Mark all entries with this frequency. Notify user
- * space and arrange for notification when the radar
- * indication is cleared. Then kick the NOL processing
- * thread if not already running.
+ * If doing DFS debugging (mode 2), don't bother
+ * running the rest of this function.
+ *
+ * Simply announce the presence of the radar and continue
+ * along merrily.
*/
- now = ticks;
- for (i = 0; i < ic->ic_nchans; i++) {
- struct ieee80211_channel *c = &ic->ic_channels[i];
- if (c->ic_freq == chan->ic_freq) {
- c->ic_state &= ~IEEE80211_CHANSTATE_CACDONE;
- c->ic_state |= IEEE80211_CHANSTATE_RADAR;
- dfs->nol_event[i] = now;
+ if (ieee80211_dfs_debug == DFS_DBG_NOCSANOL) {
+ announce_radar(ic->ic_ifp, chan, chan);
+ ieee80211_notify_radar(ic, chan);
+ return;
+ }
+
+ /*
+ * Don't mark the channel and don't put it into NOL
+ * if we're doing DFS debugging.
+ */
+ if (ieee80211_dfs_debug == DFS_DBG_NONE) {
+ /*
+ * Mark all entries with this frequency. Notify user
+ * space and arrange for notification when the radar
+ * indication is cleared. Then kick the NOL processing
+ * thread if not already running.
+ */
+ now = ticks;
+ for (i = 0; i < ic->ic_nchans; i++) {
+ struct ieee80211_channel *c = &ic->ic_channels[i];
+ if (c->ic_freq == chan->ic_freq) {
+ c->ic_state &= ~IEEE80211_CHANSTATE_CACDONE;
+ c->ic_state |= IEEE80211_CHANSTATE_RADAR;
+ dfs->nol_event[i] = now;
+ }
}
+ ieee80211_notify_radar(ic, chan);
+ chan->ic_state |= IEEE80211_CHANSTATE_NORADAR;
+ if (!callout_pending(&dfs->nol_timer))
+ callout_reset(&dfs->nol_timer, NOL_TIMEOUT,
+ dfs_timeout, ic);
}
- ieee80211_notify_radar(ic, chan);
- chan->ic_state |= IEEE80211_CHANSTATE_NORADAR;
- if (!callout_pending(&dfs->nol_timer))
- callout_reset(&dfs->nol_timer, NOL_TIMEOUT, dfs_timeout, ic);
/*
* If radar is detected on the bss channel while
@@ -302,8 +353,16 @@
*/
if (chan == ic->ic_bsschan) {
/* XXX need a way to defer to user app */
- dfs->newchan = ieee80211_dfs_pickchannel(ic);
+ /*
+ * Don't flip over to a new channel if
+ * we are currently doing DFS debugging.
+ */
+ if (ieee80211_dfs_debug == DFS_DBG_NONE)
+ dfs->newchan = ieee80211_dfs_pickchannel(ic);
+ else
+ dfs->newchan = chan;
+
announce_radar(ic->ic_ifp, chan, dfs->newchan);
if (callout_pending(&dfs->cac_timer))
Modified: trunk/sys/net80211/ieee80211_dfs.h
===================================================================
--- trunk/sys/net80211/ieee80211_dfs.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_dfs.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_dfs.h 230793 2012-01-31 00:03:49Z adrian $
*/
#ifndef _NET80211_IEEE80211_DFS_H_
#define _NET80211_IEEE80211_DFS_H_
@@ -31,6 +32,12 @@
* 802.11h/DFS definitions.
*/
+typedef enum {
+ DFS_DBG_NONE = 0,
+ DFS_DBG_NONOL = 1,
+ DFS_DBG_NOCSANOL = 2
+} dfs_debug_t;
+
struct ieee80211_dfs_state {
int nol_event[IEEE80211_CHAN_MAX];
struct callout nol_timer; /* NOL list processing */
Modified: trunk/sys/net80211/ieee80211_freebsd.c
===================================================================
--- trunk/sys/net80211/ieee80211_freebsd.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_freebsd.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.6 2013/01/17 23:29:38 laffer1 Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_freebsd.c 259174 2013-12-10 13:38:39Z gavin $");
/*
* IEEE 802.11 support (FreeBSD-specific code)
@@ -65,6 +66,11 @@
static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state");
+#if __FreeBSD_version >= 1000020
+static const char wlanname[] = "wlan";
+static struct if_clone *wlan_cloner;
+#endif
+
/*
* Allocate/free com structure in conjunction with ifnet;
* these routines are registered with if_register_com_alloc
@@ -129,10 +135,19 @@
if_printf(ifp, "TDMA not supported\n");
return EOPNOTSUPP;
}
+#if __FreeBSD_version >= 1000020
+ vap = ic->ic_vap_create(ic, wlanname, unit,
+ cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
+ cp.icp_flags & IEEE80211_CLONE_MACADDR ?
+ cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp));
+#else
vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
cp.icp_flags & IEEE80211_CLONE_MACADDR ?
cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp));
+
+#endif
+
return (vap == NULL ? EIO : 0);
}
@@ -144,12 +159,21 @@
ic->ic_vap_delete(vap);
}
+
+#if __FreeBSD_version < 1000020
IFC_SIMPLE_DECLARE(wlan, 0);
+#endif
void
ieee80211_vap_destroy(struct ieee80211vap *vap)
{
+ CURVNET_SET(vap->iv_ifp->if_vnet);
+#if __FreeBSD_version >= 1000020
+ if_clone_destroyif(wlan_cloner, vap->iv_ifp);
+#else
if_clone_destroyif(&wlan_cloner, vap->iv_ifp);
+#endif
+ CURVNET_RESTORE();
}
int
@@ -409,6 +433,7 @@
return m;
}
+#ifndef __NO_STRICT_ALIGNMENT
/*
* Re-align the payload in the mbuf. This is mainly used (right now)
* to handle IP header alignment requirements on certain architectures.
@@ -422,9 +447,9 @@
pktlen = m->m_pkthdr.len;
space = pktlen + align;
if (space < MINCLSIZE)
- n = m_gethdr(M_DONTWAIT, MT_DATA);
+ n = m_gethdr(M_NOWAIT, MT_DATA);
else {
- n = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+ n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
space <= MCLBYTES ? MCLBYTES :
#if MJUMPAGESIZE != MCLBYTES
space <= MJUMPAGESIZE ? MJUMPAGESIZE :
@@ -445,6 +470,7 @@
m_freem(m);
return n;
}
+#endif /* !__NO_STRICT_ALIGNMENT */
int
ieee80211_add_callback(struct mbuf *m,
@@ -479,6 +505,44 @@
}
}
+/*
+ * Transmit a frame to the parent interface.
+ *
+ * TODO: if the transmission fails, make sure the parent node is freed
+ * (the callers will first need modifying.)
+ */
+int
+ieee80211_parent_xmitpkt(struct ieee80211com *ic,
+ struct mbuf *m)
+{
+ struct ifnet *parent = ic->ic_ifp;
+ /*
+ * Assert the IC TX lock is held - this enforces the
+ * processing -> queuing order is maintained
+ */
+ IEEE80211_TX_LOCK_ASSERT(ic);
+
+ return (parent->if_transmit(parent, m));
+}
+
+/*
+ * Transmit a frame to the VAP interface.
+ */
+int
+ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
+{
+ struct ifnet *ifp = vap->iv_ifp;
+
+ /*
+ * When transmitting via the VAP, we shouldn't hold
+ * any IC TX lock as the VAP TX path will acquire it.
+ */
+ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
+
+ return (ifp->if_transmit(ifp, m));
+
+}
+
#include <sys/libkern.h>
void
@@ -571,8 +635,8 @@
struct ifnet *ifp = vap->iv_ifp;
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
- "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
- k->wk_cipher->ic_name, (intmax_t) rsc,
+ "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
+ k->wk_cipher->ic_name, tid, (intmax_t) rsc,
(intmax_t) k->wk_keyrsc[tid],
k->wk_keyix, k->wk_rxkeyix);
@@ -639,7 +703,9 @@
iev.iev_ieee = c->ic_ieee;
iev.iev_mode = mode;
iev.iev_count = count;
+ CURVNET_SET(ifp->if_vnet);
rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
+ CURVNET_RESTORE();
}
void
@@ -653,7 +719,9 @@
iev.iev_flags = c->ic_flags;
iev.iev_freq = c->ic_freq;
iev.iev_ieee = c->ic_ieee;
+ CURVNET_SET(ifp->if_vnet);
rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
+ CURVNET_RESTORE();
}
void
@@ -668,7 +736,9 @@
iev.iev_freq = c->ic_freq;
iev.iev_ieee = c->ic_ieee;
iev.iev_type = type;
+ CURVNET_SET(ifp->if_vnet);
rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
+ CURVNET_RESTORE();
}
void
@@ -704,7 +774,9 @@
IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
iev.iev_cc[0] = cc[0];
iev.iev_cc[1] = cc[1];
+ CURVNET_SET(ifp->if_vnet);
rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
+ CURVNET_RESTORE();
}
void
@@ -715,7 +787,9 @@
memset(&iev, 0, sizeof(iev));
iev.iev_state = state;
+ CURVNET_SET(ifp->if_vnet);
rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
+ CURVNET_RESTORE();
}
void
@@ -735,8 +809,9 @@
static void
bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
{
- /* NB: identify vap's by if_start */
- if (dlt == DLT_IEEE802_11_RADIO && ifp->if_start == ieee80211_start) {
+ /* NB: identify vap's by if_init */
+ if (dlt == DLT_IEEE802_11_RADIO &&
+ ifp->if_init == ieee80211_init) {
struct ieee80211vap *vap = ifp->if_softc;
/*
* Track bpf radiotap listener state. We mark the vap
@@ -806,12 +881,21 @@
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
return ENOMEM;
}
+#if __FreeBSD_version >= 1000020
+ wlan_cloner = if_clone_simple(wlanname, wlan_clone_create,
+ wlan_clone_destroy, 0);
+#else
if_clone_attach(&wlan_cloner);
+#endif
if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
return 0;
case MOD_UNLOAD:
if_deregister_com_alloc(IFT_IEEE80211);
+#if __FreeBSD_version >= 1000020
+ if_clone_detach(wlan_cloner);
+#else
if_clone_detach(&wlan_cloner);
+#endif
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
return 0;
@@ -820,7 +904,11 @@
}
static moduledata_t wlan_mod = {
+#if __FreeBSD_version >= 1000020
+ wlanname,
+#else
"wlan",
+#endif
wlan_modevent,
0
};
@@ -827,3 +915,7 @@
DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(wlan, 1);
MODULE_DEPEND(wlan, ether, 1, 1, 1);
+#ifdef IEEE80211_ALQ
+MODULE_DEPEND(wlan, alq, 1, 1, 1);
+#endif /* IEEE80211_ALQ */
+
Modified: trunk/sys/net80211/ieee80211_freebsd.h
===================================================================
--- trunk/sys/net80211/ieee80211_freebsd.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_freebsd.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2003-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_freebsd.h 254640 2013-08-22 05:53:47Z adrian $
*/
#ifndef _NET80211_IEEE80211_FREEBSD_H_
#define _NET80211_IEEE80211_FREEBSD_H_
@@ -53,8 +54,34 @@
#define IEEE80211_UNLOCK(_ic) mtx_unlock(IEEE80211_LOCK_OBJ(_ic))
#define IEEE80211_LOCK_ASSERT(_ic) \
mtx_assert(IEEE80211_LOCK_OBJ(_ic), MA_OWNED)
+#define IEEE80211_UNLOCK_ASSERT(_ic) \
+ mtx_assert(IEEE80211_LOCK_OBJ(_ic), MA_NOTOWNED)
/*
+ * Transmit lock.
+ *
+ * This is a (mostly) temporary lock designed to serialise all of the
+ * transmission operations throughout the stack.
+ */
+typedef struct {
+ char name[16]; /* e.g. "ath0_com_lock" */
+ struct mtx mtx;
+} ieee80211_tx_lock_t;
+#define IEEE80211_TX_LOCK_INIT(_ic, _name) do { \
+ ieee80211_tx_lock_t *cl = &(_ic)->ic_txlock; \
+ snprintf(cl->name, sizeof(cl->name), "%s_tx_lock", _name); \
+ mtx_init(&cl->mtx, cl->name, NULL, MTX_DEF); \
+} while (0)
+#define IEEE80211_TX_LOCK_OBJ(_ic) (&(_ic)->ic_txlock.mtx)
+#define IEEE80211_TX_LOCK_DESTROY(_ic) mtx_destroy(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_LOCK(_ic) mtx_lock(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_UNLOCK(_ic) mtx_unlock(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_LOCK_ASSERT(_ic) \
+ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_OWNED)
+#define IEEE80211_TX_UNLOCK_ASSERT(_ic) \
+ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_NOTOWNED)
+
+/*
* Node locking definitions.
*/
typedef struct {
@@ -208,9 +235,25 @@
#define M_FF M_PROTO6 /* fast frame */
#define M_TXCB M_PROTO7 /* do tx complete callback */
#define M_AMPDU_MPDU M_PROTO8 /* ok for A-MPDU aggregation */
+
+/*
+ * FreeBSD-HEAD from 1000046 retired M_*FRAG* flags and turned them
+ * into header flags instead. So, we use the new protocol-specific
+ * flags.
+ *
+ * Earlier FreeBSD versions overload M_FRAG, M_FIRSTFRAG and M_LASTFRAG.
+ *
+ * XXX TODO: rename these fields so there are no namespace clashes!
+ */
+#if __FreeBSD_version >= 1000046
+#define M_FRAG M_PROTO9 /* frame fragmentation */
+#define M_FIRSTFRAG M_PROTO10 /* first frame fragment */
+#define M_LASTFRAG M_PROTO11 /* last frame fragment */
+#endif
+
#define M_80211_TX \
- (M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_ENCAP|M_EAPOL|M_PWR_SAV|\
- M_MORE_DATA|M_FF|M_TXCB|M_AMPDU_MPDU)
+ (M_ENCAP|M_EAPOL|M_PWR_SAV|M_MORE_DATA|M_FF|M_TXCB| \
+ M_AMPDU_MPDU|M_FRAG|M_FIRSTFRAG|M_LASTFRAG)
/* rx path usage */
#define M_AMPDU M_PROTO1 /* A-MPDU subframe */
@@ -220,17 +263,22 @@
#endif
#define M_80211_RX (M_AMPDU|M_WEP|M_AMPDU_MPDU)
+#if __FreeBSD_version >= 1000046
#define IEEE80211_MBUF_TX_FLAG_BITS \
- "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY\5M_ENCAP\6M_WEP\7M_EAPOL" \
- "\10M_PWR_SAV\11M_MORE_DATA\12M_BCAST\13M_MCAST\14M_FRAG\15M_FIRSTFRAG" \
- "\16M_LASTFRAG\17M_SKIP_FIREWALL\20M_FREELIST\21M_VLANTAG\22M_PROMISC" \
- "\23M_NOFREE\24M_FF\25M_TXCB\26M_AMPDU_MPDU\27M_FLOWID"
+ M_FLAG_BITS \
+ "\15M_ENCAP\17M_EAPOL\20M_PWR_SAV\21M_MORE_DATA\22M_FF\23M_TXCB" \
+ "\24M_AMPDU_MPDU\25M_FRAG\26M_FIRSTFRAG\27M_LASTFRAG"
+#else
+/* There aren't any flag bits available for versions before this */
+/* XXX TODO: implement M_FLAG_BITS for this! */
+#define IEEE80211_MBUF_TX_FLAG_BITS \
+ "\15M_ENCAP\17M_EAPOL\20M_PWR_SAV\21M_MORE_DATA\22M_FF\23M_TXCB" \
+ "\24M_AMPDU_MPDU"
+#endif
#define IEEE80211_MBUF_RX_FLAG_BITS \
- "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY\5M_AMPDU\6M_WEP\7M_PROTO3" \
- "\10M_PROTO4\11M_PROTO5\12M_BCAST\13M_MCAST\14M_FRAG\15M_FIRSTFRAG" \
- "\16M_LASTFRAG\17M_SKIP_FIREWALL\20M_FREELIST\21M_VLANTAG\22M_PROMISC" \
- "\23M_NOFREE\24M_PROTO6\25M_PROTO7\26M_AMPDU_MPDU\27M_FLOWID"
+ M_FLAG_BITS \
+ "\15M_AMPDU\16M_WEP\24M_AMPDU_MPDU"
/*
* Store WME access control bits in the vlan tag.
@@ -270,10 +318,12 @@
void (*func)(struct ieee80211_node *, void *, int), void *arg);
void ieee80211_process_callback(struct ieee80211_node *, struct mbuf *, int);
+struct ieee80211com;
+int ieee80211_parent_xmitpkt(struct ieee80211com *, struct mbuf *);
+int ieee80211_vap_xmitpkt(struct ieee80211vap *, struct mbuf *);
+
void get_random_bytes(void *, size_t);
-struct ieee80211com;
-
void ieee80211_sysctl_attach(struct ieee80211com *);
void ieee80211_sysctl_detach(struct ieee80211com *);
void ieee80211_sysctl_vattach(struct ieee80211vap *);
Modified: trunk/sys/net80211/ieee80211_hostap.c
===================================================================
--- trunk/sys/net80211/ieee80211_hostap.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_hostap.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_hostap.c 262007 2014-02-17 01:36:53Z kevlo $");
#endif
/*
@@ -73,7 +74,6 @@
static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int rssi, int nf);
static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
-static void hostap_recv_pspoll(struct ieee80211_node *, struct mbuf *);
void
ieee80211_hostap_attach(struct ieee80211com *ic)
@@ -100,6 +100,7 @@
vap->iv_recv_ctl = hostap_recv_ctl;
vap->iv_opdetach = hostap_vdetach;
vap->iv_deliver_data = hostap_deliver_data;
+ vap->iv_recv_pspoll = ieee80211_recv_pspoll;
}
static void
@@ -355,7 +356,12 @@
struct ifnet *ifp = vap->iv_ifp;
/* clear driver/net80211 flags before passing up */
+#if __FreeBSD_version >= 1000046
+ m->m_flags &= ~(M_MCAST | M_BCAST);
+ m_clrprotoflags(m);
+#else
m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
+#endif
KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP,
("gack, opmode %d", vap->iv_opmode));
@@ -376,7 +382,7 @@
struct mbuf *mcopy = NULL;
if (m->m_flags & M_MCAST) {
- mcopy = m_dup(m, M_DONTWAIT);
+ mcopy = m_dup(m, M_NOWAIT);
if (mcopy == NULL)
ifp->if_oerrors++;
else
@@ -412,7 +418,7 @@
if (mcopy != NULL) {
int len, err;
len = mcopy->m_pkthdr.len;
- err = ifp->if_transmit(ifp, mcopy);
+ err = ieee80211_vap_xmitpkt(vap, mcopy);
if (err) {
/* NB: IFQ_HANDOFF reclaims mcopy */
} else {
@@ -645,7 +651,7 @@
*/
if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^
(ni->ni_flags & IEEE80211_NODE_PWR_MGT)))
- ieee80211_node_pwrsave(ni,
+ vap->iv_node_ps(ni,
wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);
/*
* For 4-address packets handle WDS discovery
@@ -688,7 +694,7 @@
* crypto cipher modules used to do delayed update
* of replay sequence numbers.
*/
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
/*
* Discard encrypted frames when privacy is off.
@@ -706,7 +712,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
} else {
/* XXX M_WEP and IEEE80211_F_PRIVACY */
key = NULL;
@@ -850,7 +856,7 @@
ether_sprintf(wh->i_addr2), rssi);
}
#endif
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
/*
* Only shared key auth frames with a challenge
@@ -878,7 +884,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
}
/*
* Pass the packet to radiotap before calling iv_recv_mgmt().
@@ -1795,6 +1801,15 @@
return;
}
/*
+ * Consult the ACL policy module if setup.
+ */
+ if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
+ wh, NULL, "%s", "disallowed by ACL");
+ vap->iv_stats.is_rx_acl++;
+ return;
+ }
+ /*
* prreq frame format
* [tlv] ssid
* [tlv] supported rates
@@ -1873,8 +1888,7 @@
/*
* Consult the ACL policy module if setup.
*/
- if (vap->iv_acl != NULL &&
- !vap->iv_acl->iac_check(vap, wh->i_addr2)) {
+ if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
wh, NULL, "%s", "disallowed by ACL");
vap->iv_stats.is_rx_acl++;
@@ -2232,7 +2246,7 @@
{
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_PS_POLL:
- hostap_recv_pspoll(ni, m);
+ ni->ni_vap->iv_recv_pspoll(ni, m);
break;
case IEEE80211_FC0_SUBTYPE_BAR:
ieee80211_recv_bar(ni, m);
@@ -2243,12 +2257,12 @@
/*
* Process a received ps-poll frame.
*/
-static void
-hostap_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0)
+void
+ieee80211_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0)
{
struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_frame_min *wh;
- struct ifnet *ifp;
struct mbuf *m;
uint16_t aid;
int qlen;
@@ -2312,10 +2326,15 @@
}
m->m_flags |= M_PWR_SAV; /* bypass PS handling */
- if (m->m_flags & M_ENCAP)
- ifp = vap->iv_ic->ic_ifp;
- else
- ifp = vap->iv_ifp;
- IF_ENQUEUE(&ifp->if_snd, m);
- if_start(ifp);
+ /*
+ * Do the right thing; if it's an encap'ed frame then
+ * call ieee80211_parent_xmitpkt() (and free the ref) else
+ * call ieee80211_vap_xmitpkt().
+ */
+ if (m->m_flags & M_ENCAP) {
+ if (ieee80211_parent_xmitpkt(ic, m) != 0)
+ ieee80211_free_node(ni);
+ } else {
+ (void) ieee80211_vap_xmitpkt(vap, m);
+ }
}
Modified: trunk/sys/net80211/ieee80211_hostap.h
===================================================================
--- trunk/sys/net80211/ieee80211_hostap.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_hostap.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_hostap.h 241138 2012-10-02 17:45:19Z adrian $
*/
#ifndef _NET80211_IEEE80211_HOSTAP_H_
#define _NET80211_IEEE80211_HOSTAP_H_
@@ -32,4 +33,10 @@
*/
void ieee80211_hostap_attach(struct ieee80211com *);
void ieee80211_hostap_detach(struct ieee80211com *);
+
+/*
+ * This method can be overridden
+ */
+void ieee80211_recv_pspoll(struct ieee80211_node *, struct mbuf *);
+
#endif /* !_NET80211_IEEE80211_HOSTAP_H_ */
Modified: trunk/sys/net80211/ieee80211_ht.c
===================================================================
--- trunk/sys/net80211/ieee80211_ht.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ht.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ht.c 314667 2017-03-04 13:03:31Z avg $");
#endif
/*
@@ -154,7 +155,7 @@
&ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I",
"ADDBA request backoff (ms)");
static int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
-SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW,
&ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
@@ -1023,8 +1024,13 @@
ieee80211_ht_node_init(struct ieee80211_node *ni)
{
struct ieee80211_tx_ampdu *tap;
- int ac;
+ int tid;
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+ ni,
+ "%s: called",
+ __func__);
+
if (ni->ni_flags & IEEE80211_NODE_HT) {
/*
* Clean AMPDU state on re-associate. This handles the case
@@ -1031,11 +1037,15 @@
* where a station leaves w/o notifying us and then returns
* before node is reaped for inactivity.
*/
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+ ni,
+ "%s: calling cleanup",
+ __func__);
ieee80211_ht_node_cleanup(ni);
}
- for (ac = 0; ac < WME_NUM_AC; ac++) {
- tap = &ni->ni_tx_ampdu[ac];
- tap->txa_ac = ac;
+ for (tid = 0; tid < WME_NUM_TID; tid++) {
+ tap = &ni->ni_tx_ampdu[tid];
+ tap->txa_tid = tid;
tap->txa_ni = ni;
/* NB: further initialization deferred */
}
@@ -1052,10 +1062,15 @@
struct ieee80211com *ic = ni->ni_ic;
int i;
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+ ni,
+ "%s: called",
+ __func__);
+
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
/* XXX optimize this */
- for (i = 0; i < WME_NUM_AC; i++) {
+ for (i = 0; i < WME_NUM_TID; i++) {
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
if (tap->txa_flags & IEEE80211_AGGR_SETUP)
ampdu_tx_stop(tap);
@@ -1160,7 +1175,7 @@
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tx_ampdu *tap;
- int ac;
+ int tid;
KASSERT(vap->iv_flags_ht & IEEE80211_FHT_HT, ("no HT requested"));
@@ -1198,9 +1213,9 @@
ni->ni_htopmode = 0; /* XXX need protection state */
ni->ni_htstbc = 0; /* XXX need info */
- for (ac = 0; ac < WME_NUM_AC; ac++) {
- tap = &ni->ni_tx_ampdu[ac];
- tap->txa_ac = ac;
+ for (tid = 0; tid < WME_NUM_TID; tid++) {
+ tap = &ni->ni_tx_ampdu[tid];
+ tap->txa_tid = tid;
}
/* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
@@ -1428,12 +1443,13 @@
* required channel change is done (e.g. in sta mode when
* parsing the contents of a beacon frame).
*/
-static void
+static int
htinfo_update_chw(struct ieee80211_node *ni, int htflags)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *c;
int chanflags;
+ int ret = 0;
chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
if (chanflags != ni->ni_chan->ic_flags) {
@@ -1460,11 +1476,13 @@
IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
c->ic_freq, c->ic_flags);
ni->ni_chan = c;
+ ret = 1;
}
/* NB: caller responsible for forcing any channel change */
}
/* update node's tx channel width */
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
+ return (ret);
}
/*
@@ -1515,7 +1533,7 @@
* Parse and update HT-related state extracted from
* the HT cap and info ie's.
*/
-void
+int
ieee80211_ht_updateparams(struct ieee80211_node *ni,
const uint8_t *htcapie, const uint8_t *htinfoie)
{
@@ -1522,6 +1540,7 @@
struct ieee80211vap *vap = ni->ni_vap;
const struct ieee80211_ie_htinfo *htinfo;
int htflags;
+ int ret = 0;
ieee80211_parse_htcap(ni, htcapie);
if (vap->iv_htcaps & IEEE80211_HTCAP_SMPS)
@@ -1543,7 +1562,8 @@
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
htflags = IEEE80211_CHAN_HT40D;
}
- htinfo_update_chw(ni, htflags);
+ if (htinfo_update_chw(ni, htflags))
+ ret = 1;
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
(vap->iv_flags_ht & IEEE80211_FHT_RIFS))
@@ -1550,6 +1570,8 @@
ni->ni_flags |= IEEE80211_NODE_RIFS;
else
ni->ni_flags &= ~IEEE80211_NODE_RIFS;
+
+ return (ret);
}
/*
@@ -1578,7 +1600,7 @@
else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
htflags = IEEE80211_CHAN_HT40D;
}
- htinfo_update_chw(ni, htflags);
+ (void) htinfo_update_chw(ni, htflags);
}
/*
@@ -1667,7 +1689,7 @@
static void
ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
{
- callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
+ callout_init(&tap->txa_timer, 1);
tap->txa_flags |= IEEE80211_AGGR_SETUP;
}
@@ -1677,8 +1699,14 @@
struct ieee80211_node *ni = tap->txa_ni;
struct ieee80211com *ic = ni->ni_ic;
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: called",
+ __func__);
+
KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
- ("txa_flags 0x%x ac %d", tap->txa_flags, tap->txa_ac));
+ ("txa_flags 0x%x tid %d ac %d", tap->txa_flags, tap->txa_tid,
+ TID_TO_WME_AC(tap->txa_tid)));
/*
* Stop BA stream if setup so driver has a chance
@@ -1891,7 +1919,7 @@
struct ieee80211_tx_ampdu *tap;
uint8_t dialogtoken, policy;
uint16_t baparamset, batimeout, code;
- int tid, ac, bufsiz;
+ int tid, bufsiz;
dialogtoken = frm[2];
code = LE_READ_2(frm+3);
@@ -1901,8 +1929,7 @@
policy = MS(baparamset, IEEE80211_BAPS_POLICY);
batimeout = LE_READ_2(frm+7);
- ac = TID_TO_WME_AC(tid);
- tap = &ni->ni_tx_ampdu[ac];
+ tap = &ni->ni_tx_ampdu[tid];
if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
IEEE80211_DISCARD_MAC(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
@@ -1965,7 +1992,7 @@
struct ieee80211_rx_ampdu *rap;
struct ieee80211_tx_ampdu *tap;
uint16_t baparamset, code;
- int tid, ac;
+ int tid;
baparamset = LE_READ_2(frm+2);
code = LE_READ_2(frm+4);
@@ -1978,8 +2005,7 @@
MS(baparamset, IEEE80211_DELBAPS_INIT), code);
if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
- ac = TID_TO_WME_AC(tid);
- tap = &ni->ni_tx_ampdu[ac];
+ tap = &ni->ni_tx_ampdu[tid];
ic->ic_addba_stop(ni, tap);
} else {
rap = &ni->ni_rx_ampdu[tid];
@@ -2051,7 +2077,8 @@
{
struct ieee80211vap *vap = ni->ni_vap;
- if (tap->txa_avgpps < vap->iv_ampdu_mintraffic[tap->txa_ac])
+ if (tap->txa_avgpps <
+ vap->iv_ampdu_mintraffic[TID_TO_WME_AC(tap->txa_tid)])
return 0;
/* XXX check rssi? */
if (tap->txa_attempts >= ieee80211_addba_maxtries &&
@@ -2064,8 +2091,9 @@
return 0;
}
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
- "enable AMPDU on %s, avgpps %d pkts %d",
- ieee80211_wme_acnames[tap->txa_ac], tap->txa_avgpps, tap->txa_pkts);
+ "enable AMPDU on tid %d (%s), avgpps %d pkts %d",
+ tap->txa_tid, ieee80211_wme_acnames[TID_TO_WME_AC(tap->txa_tid)],
+ tap->txa_avgpps, tap->txa_pkts);
return 1;
}
@@ -2092,7 +2120,7 @@
tap->txa_flags &= ~IEEE80211_AGGR_NAK;
dialogtoken = (tokens+1) % 63; /* XXX */
- tid = WME_AC_TO_TID(tap->txa_ac);
+ tid = tap->txa_tid;
tap->txa_start = ni->ni_txseqs[tid];
args[0] = dialogtoken;
@@ -2106,8 +2134,8 @@
if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
/* unable to setup state, don't make request */
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
- ni, "%s: could not setup BA stream for AC %d",
- __func__, tap->txa_ac);
+ ni, "%s: could not setup BA stream for TID %d AC %d",
+ __func__, tap->txa_tid, TID_TO_WME_AC(tap->txa_tid));
/* defer next try so we don't slam the driver with requests */
tap->txa_attempts = ieee80211_addba_maxtries;
/* NB: check in case driver wants to override */
@@ -2140,12 +2168,12 @@
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
if (IEEE80211_AMPDU_RUNNING(tap)) {
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni, "%s: stop BA stream for AC %d (reason %d)",
- __func__, tap->txa_ac, reason);
+ ni, "%s: stop BA stream for TID %d (reason %d)",
+ __func__, tap->txa_tid, reason);
vap->iv_stats.is_ampdu_stop++;
ic->ic_addba_stop(ni, tap);
- args[0] = WME_AC_TO_TID(tap->txa_ac);
+ args[0] = tap->txa_tid;
args[1] = IEEE80211_DELBAPS_INIT;
args[2] = reason; /* XXX reason code */
ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
@@ -2152,12 +2180,15 @@
IEEE80211_ACTION_BA_DELBA, args);
} else {
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni, "%s: BA stream for AC %d not running (reason %d)",
- __func__, tap->txa_ac, reason);
+ ni, "%s: BA stream for TID %d not running (reason %d)",
+ __func__, tap->txa_tid, reason);
vap->iv_stats.is_ampdu_stop_failed++;
}
}
+/* XXX */
+static void bar_start_timer(struct ieee80211_tx_ampdu *tap);
+
static void
bar_timeout(void *arg)
{
@@ -2169,21 +2200,54 @@
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
ni, "%s: tid %u flags 0x%x attempts %d", __func__,
- tap->txa_ac, tap->txa_flags, tap->txa_attempts);
+ tap->txa_tid, tap->txa_flags, tap->txa_attempts);
/* guard against race with bar_tx_complete */
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
return;
/* XXX ? */
- if (tap->txa_attempts >= ieee80211_bar_maxtries)
+ if (tap->txa_attempts >= ieee80211_bar_maxtries) {
+ struct ieee80211com *ic = ni->ni_ic;
+
+ ni->ni_vap->iv_stats.is_ampdu_bar_tx_fail++;
+ /*
+ * If (at least) the last BAR TX timeout was due to
+ * an ieee80211_send_bar() failures, then we need
+ * to make sure we notify the driver that a BAR
+ * TX did occur and fail. This gives the driver
+ * a chance to undo any queue pause that may
+ * have occured.
+ */
+ ic->ic_bar_response(ni, tap, 1);
ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
- else
- ieee80211_send_bar(ni, tap, tap->txa_seqpending);
+ } else {
+ ni->ni_vap->iv_stats.is_ampdu_bar_tx_retry++;
+ if (ieee80211_send_bar(ni, tap, tap->txa_seqpending) != 0) {
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+ ni, "%s: failed to TX, starting timer\n",
+ __func__);
+ /*
+ * If ieee80211_send_bar() fails here, the
+ * timer may have stopped and/or the pending
+ * flag may be clear. Because of this,
+ * fake the BARPEND and reset the timer.
+ * A retransmission attempt will then occur
+ * during the next timeout.
+ */
+ /* XXX locking */
+ tap->txa_flags |= IEEE80211_AGGR_BARPEND;
+ bar_start_timer(tap);
+ }
+ }
}
static void
bar_start_timer(struct ieee80211_tx_ampdu *tap)
{
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: called",
+ __func__);
callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
}
@@ -2190,6 +2254,10 @@
static void
bar_stop_timer(struct ieee80211_tx_ampdu *tap)
{
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: called",
+ __func__);
callout_stop(&tap->txa_timer);
}
@@ -2200,9 +2268,10 @@
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
ni, "%s: tid %u flags 0x%x pending %d status %d",
- __func__, tap->txa_ac, tap->txa_flags,
+ __func__, tap->txa_tid, tap->txa_flags,
callout_pending(&tap->txa_timer), status);
+ ni->ni_vap->iv_stats.is_ampdu_bar_tx++;
/* XXX locking */
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
callout_pending(&tap->txa_timer)) {
@@ -2220,6 +2289,10 @@
struct ieee80211_tx_ampdu *tap, int status)
{
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: called",
+ __func__);
if (status == 0) { /* got ACK */
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
@@ -2226,7 +2299,7 @@
tap->txa_start,
IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
tap->txa_qframes, tap->txa_seqpending,
- WME_AC_TO_TID(tap->txa_ac));
+ tap->txa_tid);
/* NB: timer already stopped in bar_tx_complete */
tap->txa_start = tap->txa_seqpending;
@@ -2254,6 +2327,12 @@
uint8_t *frm;
int tid, ret;
+
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: called",
+ __func__);
+
if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
/* no ADDBA response, should not happen */
/* XXX stat+msg */
@@ -2281,7 +2360,7 @@
IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
- tid = WME_AC_TO_TID(tap->txa_ac);
+ tid = tap->txa_tid;
barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
0 : IEEE80211_BAR_NOACK)
| IEEE80211_BAR_COMP
@@ -2314,10 +2393,16 @@
* ic_raw_xmit will free the node reference
* regardless of queue/TX success or failure.
*/
- ret = ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_TX_LOCK(ic);
+ ret = ieee80211_raw_output(vap, ni, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
if (ret != 0) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
+ ni, "send BAR: failed: (ret = %d)\n",
+ ret);
/* xmit failed, clear state flag */
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
+ vap->iv_stats.is_ampdu_bar_tx_fail++;
return ret;
}
/* XXX hack against tx complete happening before timer is started */
@@ -2325,6 +2410,11 @@
bar_start_timer(tap);
return 0;
bad:
+ IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
+ tap->txa_ni,
+ "%s: bad! ret=%d",
+ __func__, ret);
+ vap->iv_stats.is_ampdu_bar_tx_fail++;
ieee80211_free_node(ni);
return ret;
#undef senderr
@@ -2684,11 +2774,15 @@
struct ieee80211_beacon_offsets *bo)
{
#define PROTMODE (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
- const struct ieee80211_channel *bsschan = vap->iv_bss->ni_chan;
+ struct ieee80211_node *ni;
+ const struct ieee80211_channel *bsschan;
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_ie_htinfo *ht =
(struct ieee80211_ie_htinfo *) bo->bo_htinfo;
+ ni = ieee80211_ref_node(vap->iv_bss);
+ bsschan = ni->ni_chan;
+
/* XXX only update on channel change */
ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
@@ -2707,6 +2801,8 @@
/* protection mode */
ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
+ ieee80211_free_node(ni);
+
/* XXX propagate to vendor ie's */
#undef PROTMODE
}
Modified: trunk/sys/net80211/ieee80211_ht.h
===================================================================
--- trunk/sys/net80211/ieee80211_ht.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ht.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_ht.h 234324 2012-04-15 20:29:39Z adrian $
*/
#ifndef _NET80211_IEEE80211_HT_H_
#define _NET80211_IEEE80211_HT_H_
@@ -44,7 +45,7 @@
#define IEEE80211_AGGR_SETUP 0x0008 /* deferred state setup */
#define IEEE80211_AGGR_NAK 0x0010 /* peer NAK'd ADDBA request */
#define IEEE80211_AGGR_BARPEND 0x0020 /* BAR response pending */
- uint8_t txa_ac;
+ uint8_t txa_tid;
uint8_t txa_token; /* dialog token */
int txa_lastsample; /* ticks @ last traffic sample */
int txa_pkts; /* packets over last sample interval */
@@ -184,7 +185,7 @@
void ieee80211_ht_timeout(struct ieee80211com *);
void ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
void ieee80211_parse_htinfo(struct ieee80211_node *, const uint8_t *);
-void ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
+int ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
const uint8_t *);
void ieee80211_ht_updatehtcap(struct ieee80211_node *, const uint8_t *);
int ieee80211_ampdu_request(struct ieee80211_node *,
Modified: trunk/sys/net80211/ieee80211_hwmp.c
===================================================================
--- trunk/sys/net80211/ieee80211_hwmp.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_hwmp.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 The FreeBSD Foundation
* All rights reserved.
@@ -28,12 +29,12 @@
*/
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_hwmp.c 314667 2017-03-04 13:03:31Z avg $");
#endif
/*
* IEEE 802.11s Hybrid Wireless Mesh Protocol, HWMP.
- *
+ *
* Based on March 2009, D3.0 802.11s draft spec.
*/
#include "opt_inet.h"
@@ -40,8 +41,8 @@
#include "opt_wlan.h"
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
@@ -68,9 +69,8 @@
static void hwmp_vdetach(struct ieee80211vap *);
static int hwmp_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
-static int hwmp_send_action(struct ieee80211_node *,
+static int hwmp_send_action(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
- const uint8_t [IEEE80211_ADDR_LEN],
uint8_t *, size_t);
static uint8_t * hwmp_add_meshpreq(uint8_t *,
const struct ieee80211_meshpreq_ie *);
@@ -86,30 +86,30 @@
static void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_meshpreq_ie *);
-static int hwmp_send_preq(struct ieee80211_node *,
+static int hwmp_send_preq(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
- const uint8_t [IEEE80211_ADDR_LEN],
- struct ieee80211_meshpreq_ie *);
+ struct ieee80211_meshpreq_ie *,
+ struct timeval *, struct timeval *);
static void hwmp_recv_prep(struct ieee80211vap *, struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_meshprep_ie *);
-static int hwmp_send_prep(struct ieee80211_node *,
+static int hwmp_send_prep(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
- const uint8_t [IEEE80211_ADDR_LEN],
struct ieee80211_meshprep_ie *);
static void hwmp_recv_perr(struct ieee80211vap *, struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_meshperr_ie *);
-static int hwmp_send_perr(struct ieee80211_node *,
+static int hwmp_send_perr(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
+ struct ieee80211_meshperr_ie *);
+static void hwmp_senderror(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
- struct ieee80211_meshperr_ie *);
+ struct ieee80211_mesh_route *, int);
static void hwmp_recv_rann(struct ieee80211vap *, struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_meshrann_ie *);
-static int hwmp_send_rann(struct ieee80211_node *,
+static int hwmp_send_rann(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN],
- const uint8_t [IEEE80211_ADDR_LEN],
struct ieee80211_meshrann_ie *);
static struct ieee80211_node *
hwmp_discover(struct ieee80211vap *,
@@ -139,9 +139,12 @@
typedef uint32_t ieee80211_hwmp_seq;
#define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0)
#define HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
+#define HWMP_SEQ_EQ(a, b) ((int32_t)((a)-(b)) == 0)
#define HWMP_SEQ_GT(a, b) ((int32_t)((a)-(b)) > 0)
#define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
+#define HWMP_SEQ_MAX(a, b) (a > b ? a : b)
+
/*
* Private extension of ieee80211_mesh_route.
*/
@@ -149,14 +152,16 @@
ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/
ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */
ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/
- int hr_preqretries;
+ struct timeval hr_lastpreq; /* last time we sent a PREQ */
+ struct timeval hr_lastrootconf; /* last sent PREQ root conf */
+ int hr_preqretries; /* number of discoveries */
+ int hr_lastdiscovery; /* last discovery in ticks */
};
struct ieee80211_hwmp_state {
ieee80211_hwmp_seq hs_seq; /* next seq to be used */
ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */
- struct timeval hs_lastpreq; /* last time we sent a PREQ */
+ int hs_rootmode; /* proactive HWMP */
struct timeval hs_lastperr; /* last time we sent a PERR */
- int hs_rootmode; /* proactive HWMP */
struct callout hs_roottimer;
uint8_t hs_maxhops; /* max hop count */
};
@@ -164,15 +169,21 @@
static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0,
"IEEE 802.11s HWMP parameters");
static int ieee80211_hwmp_targetonly = 0;
-SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLFLAG_RW,
&ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
-static int ieee80211_hwmp_replyforward = 1;
-SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW,
- &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs");
static int ieee80211_hwmp_pathtimeout = -1;
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"path entry lifetime (ms)");
+static int ieee80211_hwmp_maxpreq_retries = -1;
+SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, maxpreq_retries, CTLTYPE_INT | CTLFLAG_RW,
+ &ieee80211_hwmp_maxpreq_retries, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "maximum number of preq retries");
+static int ieee80211_hwmp_net_diameter_traversaltime = -1;
+SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, net_diameter_traversal_time,
+ CTLTYPE_INT | CTLFLAG_RW, &ieee80211_hwmp_net_diameter_traversaltime, 0,
+ ieee80211_sysctl_msecs_ticks, "I",
+ "estimate travelse time across the MBSS (ms)");
static int ieee80211_hwmp_roottimeout = -1;
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
@@ -185,6 +196,11 @@
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_rannint, 0, ieee80211_sysctl_msecs_ticks, "I",
"root announcement interval (ms)");
+static struct timeval ieee80211_hwmp_rootconfint = { 0, 0 };
+static int ieee80211_hwmp_rootconfint_internal = -1;
+SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootconfint, CTLTYPE_INT | CTLFLAG_RD,
+ &ieee80211_hwmp_rootconfint_internal, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "root confirmation interval (ms) (read-only)");
#define IEEE80211_HWMP_DEFAULT_MAXHOPS 31
@@ -195,6 +211,7 @@
.mpp_ie = IEEE80211_MESHCONF_PATH_HWMP,
.mpp_discover = hwmp_discover,
.mpp_peerdown = hwmp_peerdown,
+ .mpp_senderror = hwmp_senderror,
.mpp_vattach = hwmp_vattach,
.mpp_vdetach = hwmp_vdetach,
.mpp_newstate = hwmp_newstate,
@@ -208,16 +225,31 @@
static void
ieee80211_hwmp_init(void)
{
+ /* Default values as per amendment */
ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
+ ieee80211_hwmp_rootconfint_internal = msecs_to_ticks(2*1000);
+ ieee80211_hwmp_maxpreq_retries = 3;
+ /*
+ * (TU): A measurement of time equal to 1024 μs,
+ * 500 TU is 512 ms.
+ */
+ ieee80211_hwmp_net_diameter_traversaltime = msecs_to_ticks(512);
/*
+ * NB: I dont know how to make SYSCTL_PROC that calls ms to ticks
+ * and return a struct timeval...
+ */
+ ieee80211_hwmp_rootconfint.tv_usec =
+ ieee80211_hwmp_rootconfint_internal * 1000;
+
+ /*
* Register action frame handler.
*/
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPATH,
- IEEE80211_ACTION_MESHPATH_SEL, hwmp_recv_action_meshpath);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_HWMP, hwmp_recv_action_meshpath);
/* NB: default is 5 secs per spec */
mesh_proto_hwmp.mpp_inact = msecs_to_ticks(5*1000);
@@ -244,7 +276,7 @@
return;
}
hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
- callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE);
+ callout_init(&hs->hs_roottimer, 1);
vap->iv_hwmp = hs;
}
@@ -275,17 +307,114 @@
return 0;
}
+/*
+ * Verify the length of an HWMP PREQ and return the number
+ * of destinations >= 1, if verification fails -1 is returned.
+ */
static int
+verify_mesh_preq_len(struct ieee80211vap *vap,
+ const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+ int alloc_sz = -1;
+ int ndest = -1;
+ if (iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE) {
+ /* Originator External Address present */
+ alloc_sz = IEEE80211_MESHPREQ_BASE_SZ_AE;
+ ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET_AE];
+ } else {
+ /* w/o Originator External Address */
+ alloc_sz = IEEE80211_MESHPREQ_BASE_SZ;
+ ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET];
+ }
+ alloc_sz += ndest * IEEE80211_MESHPREQ_TRGT_SZ;
+
+ if(iefrm[1] != (alloc_sz)) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+ wh, NULL, "PREQ (AE=%s) with wrong len",
+ iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE ? "1" : "0");
+ return (-1);
+ }
+ return ndest;
+}
+
+/*
+ * Verify the length of an HWMP PREP and returns 1 on success,
+ * otherwise -1.
+ */
+static int
+verify_mesh_prep_len(struct ieee80211vap *vap,
+ const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+ int alloc_sz = -1;
+ if (iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE) {
+ if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ_AE)
+ alloc_sz = IEEE80211_MESHPREP_BASE_SZ_AE;
+ } else if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ)
+ alloc_sz = IEEE80211_MESHPREP_BASE_SZ;
+ if(alloc_sz < 0) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+ wh, NULL, "PREP (AE=%s) with wrong len",
+ iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE ? "1" : "0");
+ return (-1);
+ }
+ return (1);
+}
+
+/*
+ * Verify the length of an HWMP PERR and return the number
+ * of destinations >= 1, if verification fails -1 is returned.
+ */
+static int
+verify_mesh_perr_len(struct ieee80211vap *vap,
+ const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+ int alloc_sz = -1;
+ const uint8_t *iefrm_t = iefrm;
+ uint8_t ndest = iefrm_t[IEEE80211_MESHPERR_NDEST_OFFSET];
+ int i;
+
+ if(ndest > IEEE80211_MESHPERR_MAXDEST) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+ wh, NULL, "PERR with wrong number of destionat (>19), %u",
+ ndest);
+ return (-1);
+ }
+
+ iefrm_t += IEEE80211_MESHPERR_NDEST_OFFSET + 1; /* flag is next field */
+ /* We need to check each destionation flag to know size */
+ for(i = 0; i<ndest; i++) {
+ if ((*iefrm_t) & IEEE80211_MESHPERR_FLAGS_AE)
+ iefrm_t += IEEE80211_MESHPERR_DEST_SZ_AE;
+ else
+ iefrm_t += IEEE80211_MESHPERR_DEST_SZ;
+ }
+
+ alloc_sz = (iefrm_t - iefrm) - 2; /* action + code */
+ if(alloc_sz != iefrm[1]) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+ wh, NULL, "%s", "PERR with wrong len");
+ return (-1);
+ }
+ return ndest;
+}
+
+static int
hwmp_recv_action_meshpath(struct ieee80211_node *ni,
const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
struct ieee80211vap *vap = ni->ni_vap;
- struct ieee80211_meshpreq_ie preq;
- struct ieee80211_meshprep_ie prep;
- struct ieee80211_meshperr_ie perr;
+ struct ieee80211_meshpreq_ie *preq;
+ struct ieee80211_meshprep_ie *prep;
+ struct ieee80211_meshperr_ie *perr;
struct ieee80211_meshrann_ie rann;
const uint8_t *iefrm = frm + 2; /* action + code */
+ const uint8_t *iefrm_t = iefrm; /* temporary pointer */
+ int ndest = -1;
int found = 0;
while (efrm - iefrm > 1) {
@@ -293,66 +422,132 @@
switch (*iefrm) {
case IEEE80211_ELEMID_MESHPREQ:
{
- const struct ieee80211_meshpreq_ie *mpreq =
- (const struct ieee80211_meshpreq_ie *) iefrm;
- /* XXX > 1 target */
- if (mpreq->preq_len !=
- sizeof(struct ieee80211_meshpreq_ie) - 2) {
- IEEE80211_DISCARD(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
- wh, NULL, "%s", "PREQ with wrong len");
+ int i = 0;
+
+ iefrm_t = iefrm;
+ ndest = verify_mesh_preq_len(vap, wh, iefrm_t);
+ if (ndest < 0) {
vap->iv_stats.is_rx_mgtdiscard++;
break;
}
- memcpy(&preq, mpreq, sizeof(preq));
- preq.preq_id = LE_READ_4(&mpreq->preq_id);
- preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq);
- preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime);
- preq.preq_metric = LE_READ_4(&mpreq->preq_metric);
- preq.preq_targets[0].target_seq =
- LE_READ_4(&mpreq->preq_targets[0].target_seq);
- hwmp_recv_preq(vap, ni, wh, &preq);
+ preq = malloc(sizeof(*preq) +
+ (ndest - 1) * sizeof(*preq->preq_targets),
+ M_80211_MESH_PREQ, M_NOWAIT | M_ZERO);
+ KASSERT(preq != NULL, ("preq == NULL"));
+
+ preq->preq_ie = *iefrm_t++;
+ preq->preq_len = *iefrm_t++;
+ preq->preq_flags = *iefrm_t++;
+ preq->preq_hopcount = *iefrm_t++;
+ preq->preq_ttl = *iefrm_t++;
+ preq->preq_id = LE_READ_4(iefrm_t); iefrm_t += 4;
+ IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm_t);
+ iefrm_t += 6;
+ preq->preq_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+ /* NB: may have Originator Proxied Address */
+ if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(
+ preq->preq_orig_ext_addr, iefrm_t);
+ iefrm_t += 6;
+ }
+ preq->preq_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
+ preq->preq_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
+ preq->preq_tcount = *iefrm_t++;
+
+ for (i = 0; i < preq->preq_tcount; i++) {
+ preq->preq_targets[i].target_flags = *iefrm_t++;
+ IEEE80211_ADDR_COPY(
+ preq->preq_targets[i].target_addr, iefrm_t);
+ iefrm_t += 6;
+ preq->preq_targets[i].target_seq =
+ LE_READ_4(iefrm_t);
+ iefrm_t += 4;
+ }
+
+ hwmp_recv_preq(vap, ni, wh, preq);
+ free(preq, M_80211_MESH_PREQ);
found++;
- break;
+ break;
}
case IEEE80211_ELEMID_MESHPREP:
{
- const struct ieee80211_meshprep_ie *mprep =
- (const struct ieee80211_meshprep_ie *) iefrm;
- if (mprep->prep_len !=
- sizeof(struct ieee80211_meshprep_ie) - 2) {
- IEEE80211_DISCARD(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
- wh, NULL, "%s", "PREP with wrong len");
+ iefrm_t = iefrm;
+ ndest = verify_mesh_prep_len(vap, wh, iefrm_t);
+ if (ndest < 0) {
vap->iv_stats.is_rx_mgtdiscard++;
break;
}
- memcpy(&prep, mprep, sizeof(prep));
- prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq);
- prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime);
- prep.prep_metric = LE_READ_4(&mprep->prep_metric);
- prep.prep_origseq = LE_READ_4(&mprep->prep_origseq);
- hwmp_recv_prep(vap, ni, wh, &prep);
+ prep = malloc(sizeof(*prep),
+ M_80211_MESH_PREP, M_NOWAIT | M_ZERO);
+ KASSERT(prep != NULL, ("prep == NULL"));
+
+ prep->prep_ie = *iefrm_t++;
+ prep->prep_len = *iefrm_t++;
+ prep->prep_flags = *iefrm_t++;
+ prep->prep_hopcount = *iefrm_t++;
+ prep->prep_ttl = *iefrm_t++;
+ IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm_t);
+ iefrm_t += 6;
+ prep->prep_targetseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+ /* NB: May have Target Proxied Address */
+ if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(
+ prep->prep_target_ext_addr, iefrm_t);
+ iefrm_t += 6;
+ }
+ prep->prep_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
+ prep->prep_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
+ IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm_t);
+ iefrm_t += 6;
+ prep->prep_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+
+ hwmp_recv_prep(vap, ni, wh, prep);
+ free(prep, M_80211_MESH_PREP);
found++;
break;
}
case IEEE80211_ELEMID_MESHPERR:
{
- const struct ieee80211_meshperr_ie *mperr =
- (const struct ieee80211_meshperr_ie *) iefrm;
- /* XXX > 1 target */
- if (mperr->perr_len !=
- sizeof(struct ieee80211_meshperr_ie) - 2) {
- IEEE80211_DISCARD(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
- wh, NULL, "%s", "PERR with wrong len");
+ int i = 0;
+
+ iefrm_t = iefrm;
+ ndest = verify_mesh_perr_len(vap, wh, iefrm_t);
+ if (ndest < 0) {
vap->iv_stats.is_rx_mgtdiscard++;
break;
}
- memcpy(&perr, mperr, sizeof(perr));
- perr.perr_dests[0].dest_seq =
- LE_READ_4(&mperr->perr_dests[0].dest_seq);
- hwmp_recv_perr(vap, ni, wh, &perr);
+ perr = malloc(sizeof(*perr) +
+ (ndest - 1) * sizeof(*perr->perr_dests),
+ M_80211_MESH_PERR, M_NOWAIT | M_ZERO);
+ KASSERT(perr != NULL, ("perr == NULL"));
+
+ perr->perr_ie = *iefrm_t++;
+ perr->perr_len = *iefrm_t++;
+ perr->perr_ttl = *iefrm_t++;
+ perr->perr_ndests = *iefrm_t++;
+
+ for (i = 0; i<perr->perr_ndests; i++) {
+ perr->perr_dests[i].dest_flags = *iefrm_t++;
+ IEEE80211_ADDR_COPY(
+ perr->perr_dests[i].dest_addr, iefrm_t);
+ iefrm_t += 6;
+ perr->perr_dests[i].dest_seq = LE_READ_4(iefrm_t);
+ iefrm_t += 4;
+ /* NB: May have Target Proxied Address */
+ if (perr->perr_dests[i].dest_flags &
+ IEEE80211_MESHPERR_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(
+ perr->perr_dests[i].dest_ext_addr,
+ iefrm_t);
+ iefrm_t += 6;
+ }
+ perr->perr_dests[i].dest_rcode =
+ LE_READ_2(iefrm_t);
+ iefrm_t += 2;
+ }
+
+ hwmp_recv_perr(vap, ni, wh, perr);
+ free(perr, M_80211_MESH_PERR);
found++;
break;
}
@@ -365,11 +560,12 @@
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
wh, NULL, "%s", "RAN with wrong len");
- vap->iv_stats.is_rx_mgtdiscard++;
+ vap->iv_stats.is_rx_mgtdiscard++;
return 1;
}
memcpy(&rann, mrann, sizeof(rann));
rann.rann_seq = LE_READ_4(&mrann->rann_seq);
+ rann.rann_interval = LE_READ_4(&mrann->rann_interval);
rann.rann_metric = LE_READ_4(&mrann->rann_metric);
hwmp_recv_rann(vap, ni, wh, &rann);
found++;
@@ -388,17 +584,31 @@
}
static int
-hwmp_send_action(struct ieee80211_node *ni,
- const uint8_t sa[IEEE80211_ADDR_LEN],
+hwmp_send_action(struct ieee80211vap *vap,
const uint8_t da[IEEE80211_ADDR_LEN],
uint8_t *ie, size_t len)
{
- struct ieee80211vap *vap = ni->ni_vap;
- struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_node *ni;
+ struct ieee80211com *ic;
struct ieee80211_bpf_params params;
struct mbuf *m;
uint8_t *frm;
+ int ret;
+ if (IEEE80211_IS_MULTICAST(da)) {
+ ni = ieee80211_ref_node(vap->iv_bss);
+#ifdef IEEE80211_DEBUG_REFCNT
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
+ __func__, __LINE__,
+ ni, ether_sprintf(ni->ni_macaddr),
+ ieee80211_node_refcnt(ni)+1);
+#endif
+ ieee80211_ref_node(ni);
+ }
+ else
+ ni = ieee80211_mesh_find_txnode(vap, da);
+
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
"block %s frame in CAC state", "HWMP action");
@@ -407,19 +617,7 @@
}
KASSERT(ni != NULL, ("null node"));
- /*
- * Hold a reference on the node so it doesn't go away until after
- * the xmit is complete all the way in the driver. On error we
- * will remove our reference.
- */
-#ifdef IEEE80211_DEBUG_REFCNT
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
- "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
- __func__, __LINE__,
- ni, ether_sprintf(ni->ni_macaddr),
- ieee80211_node_refcnt(ni)+1);
-#endif
- ieee80211_ref_node(ni);
+ ic = ni->ni_ic;
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
@@ -430,8 +628,8 @@
vap->iv_stats.is_tx_nobuf++;
return ENOMEM;
}
- *frm++ = IEEE80211_ACTION_CAT_MESHPATH;
- *frm++ = IEEE80211_ACTION_MESHPATH_SEL;
+ *frm++ = IEEE80211_ACTION_CAT_MESH;
+ *frm++ = IEEE80211_ACTION_MESH_HWMP;
switch (*ie) {
case IEEE80211_ELEMID_MESHPREQ:
frm = hwmp_add_meshpreq(frm,
@@ -452,15 +650,18 @@
}
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
if (m == NULL) {
ieee80211_free_node(ni);
vap->iv_stats.is_tx_nobuf++;
return ENOMEM;
}
+
+ IEEE80211_TX_LOCK(ic);
+
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
- IEEE80211_NONQOS_TID, sa, da, sa);
+ IEEE80211_NONQOS_TID, vap->iv_myaddr, da, vap->iv_myaddr);
m->m_flags |= M_ENCAP; /* mark encapsulated */
IEEE80211_NODE_STAT(ni, tx_mgmt);
@@ -473,7 +674,9 @@
else
params.ibp_try0 = ni->ni_txparms->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ ret = ieee80211_raw_output(vap, ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
@@ -488,6 +691,9 @@
/*
* Add a Mesh Path Request IE to a frame.
*/
+#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags
+#define PREQ_TADDR(n) preq->preq_targets[n].target_addr
+#define PREQ_TSEQ(n) preq->preq_targets[n].target_seq
static uint8_t *
hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
{
@@ -494,8 +700,7 @@
int i;
*frm++ = IEEE80211_ELEMID_MESHPREQ;
- *frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 +
- (preq->preq_tcount - 1) * sizeof(*preq->preq_targets);
+ *frm++ = preq->preq_len; /* len already calculated */
*frm++ = preq->preq_flags;
*frm++ = preq->preq_hopcount;
*frm++ = preq->preq_ttl;
@@ -502,17 +707,24 @@
ADDWORD(frm, preq->preq_id);
IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
ADDWORD(frm, preq->preq_origseq);
+ if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(frm, preq->preq_orig_ext_addr);
+ frm += 6;
+ }
ADDWORD(frm, preq->preq_lifetime);
ADDWORD(frm, preq->preq_metric);
*frm++ = preq->preq_tcount;
for (i = 0; i < preq->preq_tcount; i++) {
- *frm++ = preq->preq_targets[i].target_flags;
- IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr);
+ *frm++ = PREQ_TFLAGS(i);
+ IEEE80211_ADDR_COPY(frm, PREQ_TADDR(i));
frm += 6;
- ADDWORD(frm, preq->preq_targets[i].target_seq);
+ ADDWORD(frm, PREQ_TSEQ(i));
}
return frm;
}
+#undef PREQ_TFLAGS
+#undef PREQ_TADDR
+#undef PREQ_TSEQ
/*
* Add a Mesh Path Reply IE to a frame.
@@ -521,12 +733,16 @@
hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
{
*frm++ = IEEE80211_ELEMID_MESHPREP;
- *frm++ = sizeof(struct ieee80211_meshprep_ie) - 2;
+ *frm++ = prep->prep_len; /* len already calculated */
*frm++ = prep->prep_flags;
*frm++ = prep->prep_hopcount;
*frm++ = prep->prep_ttl;
IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
ADDWORD(frm, prep->prep_targetseq);
+ if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(frm, prep->prep_target_ext_addr);
+ frm += 6;
+ }
ADDWORD(frm, prep->prep_lifetime);
ADDWORD(frm, prep->prep_metric);
IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
@@ -537,6 +753,11 @@
/*
* Add a Mesh Path Error IE to a frame.
*/
+#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
+#define PERR_DADDR(n) perr->perr_dests[n].dest_addr
+#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
+#define PERR_EXTADDR(n) perr->perr_dests[n].dest_ext_addr
+#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
static uint8_t *
hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
{
@@ -543,19 +764,27 @@
int i;
*frm++ = IEEE80211_ELEMID_MESHPERR;
- *frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 +
- (perr->perr_ndests - 1) * sizeof(*perr->perr_dests);
+ *frm++ = perr->perr_len; /* len already calculated */
*frm++ = perr->perr_ttl;
*frm++ = perr->perr_ndests;
for (i = 0; i < perr->perr_ndests; i++) {
- *frm++ = perr->perr_dests[i].dest_flags;
- IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
+ *frm++ = PERR_DFLAGS(i);
+ IEEE80211_ADDR_COPY(frm, PERR_DADDR(i));
frm += 6;
- ADDWORD(frm, perr->perr_dests[i].dest_seq);
- ADDSHORT(frm, perr->perr_dests[i].dest_rcode);
+ ADDWORD(frm, PERR_DSEQ(i));
+ if (PERR_DFLAGS(i) & IEEE80211_MESHPERR_FLAGS_AE) {
+ IEEE80211_ADDR_COPY(frm, PERR_EXTADDR(i));
+ frm += 6;
+ }
+ ADDSHORT(frm, PERR_DRCODE(i));
}
return frm;
}
+#undef PERR_DFLAGS
+#undef PERR_DADDR
+#undef PERR_DSEQ
+#undef PERR_EXTADDR
+#undef PERR_DRCODE
/*
* Add a Root Annoucement IE to a frame.
@@ -564,12 +793,13 @@
hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
{
*frm++ = IEEE80211_ELEMID_MESHRANN;
- *frm++ = sizeof(struct ieee80211_meshrann_ie) - 2;
+ *frm++ = rann->rann_len;
*frm++ = rann->rann_flags;
*frm++ = rann->rann_hopcount;
*frm++ = rann->rann_ttl;
IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
ADDWORD(frm, rann->rann_seq);
+ ADDWORD(frm, rann->rann_interval);
ADDWORD(frm, rann->rann_metric);
return frm;
}
@@ -578,19 +808,23 @@
hwmp_rootmode_setup(struct ieee80211vap *vap)
{
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
switch (hs->hs_rootmode) {
case IEEE80211_HWMP_ROOTMODE_DISABLED:
callout_drain(&hs->hs_roottimer);
+ ms->ms_flags &= ~IEEE80211_MESHFLAGS_ROOT;
break;
case IEEE80211_HWMP_ROOTMODE_NORMAL:
case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
hwmp_rootmode_cb, vap);
+ ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
break;
case IEEE80211_HWMP_ROOTMODE_RANN:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
hwmp_rootmode_rann_cb, vap);
+ ms->ms_flags |= IEEE80211_MESHFLAGS_ROOT;
break;
}
}
@@ -613,9 +847,9 @@
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast PREQ");
- preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
- if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
- preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
+ preq.preq_flags = 0;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE)
+ preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_GATE;
if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
preq.preq_hopcount = 0;
@@ -628,10 +862,11 @@
preq.preq_tcount = 1;
IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
- IEEE80211_MESHPREQ_TFLAGS_RF;
+ IEEE80211_MESHPREQ_TFLAGS_USN;
PREQ_TSEQ(0) = 0;
vap->iv_stats.is_hwmp_rootreqs++;
- hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
+ /* NB: we enforce rate check ourself */
+ hwmp_send_preq(vap, broadcastaddr, &preq, NULL, NULL);
hwmp_rootmode_setup(vap);
}
#undef PREQ_TFLAGS
@@ -654,19 +889,59 @@
"%s", "send broadcast RANN");
rann.rann_flags = 0;
- if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
- rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE)
+ rann.rann_flags |= IEEE80211_MESHFLAGS_GATE;
rann.rann_hopcount = 0;
rann.rann_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
rann.rann_seq = ++hs->hs_seq;
+ rann.rann_interval = ieee80211_hwmp_rannint;
rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
vap->iv_stats.is_hwmp_rootrann++;
- hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
+ hwmp_send_rann(vap, broadcastaddr, &rann);
hwmp_rootmode_setup(vap);
}
+/*
+ * Update forwarding information to TA if metric improves.
+ */
+static void
+hwmp_update_transmitter(struct ieee80211vap *vap, struct ieee80211_node *ni,
+ const char *hwmp_frame)
+{
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_route *rttran = NULL; /* Transmitter */
+ int metric = 0;
+
+ rttran = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
+ if (rttran == NULL) {
+ rttran = ieee80211_mesh_rt_add(vap, ni->ni_macaddr);
+ if (rttran == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "unable to add path to transmitter %6D of %s",
+ ni->ni_macaddr, ":", hwmp_frame);
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
+ }
+ metric = ms->ms_pmetric->mpm_metric(ni);
+ if (!(rttran->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) ||
+ rttran->rt_metric > metric)
+ {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "%s path to transmiter %6D of %s, metric %d:%d",
+ rttran->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+ "prefer" : "update", ni->ni_macaddr, ":", hwmp_frame,
+ rttran->rt_metric, metric);
+ IEEE80211_ADDR_COPY(rttran->rt_nexthop, ni->ni_macaddr);
+ rttran->rt_metric = metric;
+ rttran->rt_nhops = 1;
+ ieee80211_mesh_rt_update(rttran, ms->ms_ppath->mpp_inact);
+ rttran->rt_flags = IEEE80211_MESHRT_FLAGS_VALID;
+ }
+}
+
#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags
#define PREQ_TADDR(n) preq->preq_targets[n].target_addr
#define PREQ_TSEQ(n) preq->preq_targets[n].target_seq
@@ -675,15 +950,16 @@
const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
- struct ieee80211_mesh_route *rt = NULL;
struct ieee80211_mesh_route *rtorig = NULL;
- struct ieee80211_hwmp_route *hrorig;
+ struct ieee80211_mesh_route *rtorig_ext = NULL;
+ struct ieee80211_mesh_route *rttarg = NULL;
+ struct ieee80211_hwmp_route *hrorig = NULL;
+ struct ieee80211_hwmp_route *hrtarg = NULL;
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_meshprep_ie prep;
+ ieee80211_hwmp_seq preqid; /* last seen preqid for orig */
+ uint32_t metric = 0;
- if (ni == vap->iv_bss ||
- ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
- return;
/*
* Ignore PREQs from us. Could happen because someone forward it
* back to us.
@@ -692,104 +968,194 @@
return;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "received PREQ, source %s", ether_sprintf(preq->preq_origaddr));
+ "received PREQ, orig %6D, targ(0) %6D", preq->preq_origaddr, ":",
+ PREQ_TADDR(0), ":");
/*
- * Acceptance criteria: if the PREQ is not for us and
- * forwarding is disabled, discard this PREQ.
+ * Acceptance criteria: (if the PREQ is not for us or not broadcast,
+ * or an external mac address not proxied by us),
+ * AND forwarding is disabled, discard this PREQ.
*/
- if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) &&
- !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
+ rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
+ if (!(ms->ms_flags & IEEE80211_MESHFLAGS_FWD) &&
+ (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
+ !IEEE80211_IS_MULTICAST(PREQ_TADDR(0)) ||
+ (rttarg != NULL &&
+ rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
+ IEEE80211_ADDR_EQ(vap->iv_myaddr, rttarg->rt_mesh_gate)))) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
return;
}
+ /*
+ * Acceptance criteria: if unicast addressed
+ * AND no valid forwarding for Target of PREQ, discard this PREQ.
+ */
+ if(rttarg != NULL)
+ hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg,
+ struct ieee80211_hwmp_route);
+ /* Address mode: ucast */
+ if(preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM &&
+ rttarg == NULL &&
+ !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+ preq->preq_origaddr, NULL,
+ "unicast addressed PREQ of unknown target %6D",
+ PREQ_TADDR(0), ":");
+ return;
+ }
+
+ /* PREQ ACCEPTED */
+
rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
- if (rtorig == NULL)
+ if (rtorig == NULL) {
rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
- if (rtorig == NULL) {
- /* XXX stat */
- return;
+ if (rtorig == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "unable to add orig path to %6D",
+ preq->preq_origaddr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "adding originator %6D", preq->preq_origaddr, ":");
}
hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
- /*
- * Sequence number validation.
+
+ /* record last seen preqid */
+ preqid = hrorig->hr_preqid;
+ hrorig->hr_preqid = HWMP_SEQ_MAX(hrorig->hr_preqid, preq->preq_id);
+
+ /* Data creation and update of forwarding information
+ * according to Table 11C-8 for originator mesh STA.
*/
- if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
- HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
+ metric = preq->preq_metric + ms->ms_pmetric->mpm_metric(ni);
+ if (HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) ||
+ (HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) &&
+ metric < rtorig->rt_metric)) {
+ hrorig->hr_seq = preq->preq_origseq;
+ IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2);
+ rtorig->rt_metric = metric;
+ rtorig->rt_nhops = preq->preq_hopcount + 1;
+ ieee80211_mesh_rt_update(rtorig, preq->preq_lifetime);
+ /* Path to orig is valid now.
+ * NB: we know it can't be Proxy, and if it is GATE
+ * it will be marked below.
+ */
+ rtorig->rt_flags = IEEE80211_MESHRT_FLAGS_VALID;
+ } else if ((hrtarg != NULL &&
+ !HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0))) ||
+ (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
+ preqid >= preq->preq_id)) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREQ from %s, old seq no %u <= %u",
- ether_sprintf(preq->preq_origaddr),
- preq->preq_origseq, hrorig->hr_seq);
+ "discard PREQ from %6D, old seqno %u <= %u,"
+ " or old preqid %u < %u",
+ preq->preq_origaddr, ":",
+ preq->preq_origseq, hrorig->hr_seq,
+ preq->preq_id, preqid);
return;
}
- hrorig->hr_preqid = preq->preq_id;
- hrorig->hr_seq = preq->preq_origseq;
+ /* Update forwarding information to TA if metric improves. */
+ hwmp_update_transmitter(vap, ni, "PREQ");
+
/*
* Check if the PREQ is addressed to us.
+ * or a Proxy currently gated by us.
*/
- if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "reply to %s", ether_sprintf(preq->preq_origaddr));
+ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
+ (ms->ms_flags & IEEE80211_MESHFLAGS_GATE &&
+ rttarg != NULL &&
+ IEEE80211_ADDR_EQ(vap->iv_myaddr, rttarg->rt_mesh_gate) &&
+ rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
+ rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
/*
- * Build and send a PREP frame.
+ * When we are the target we shall update our own HWMP seq
+ * number with max of (current and preq->seq) + 1
*/
+ hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1;
+
prep.prep_flags = 0;
prep.prep_hopcount = 0;
+ prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
+ IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
+ if (rttarg != NULL && /* if NULL it means we are the target */
+ rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "reply for proxy %6D", rttarg->rt_dest, ":");
+ prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE;
+ IEEE80211_ADDR_COPY(prep.prep_target_ext_addr,
+ rttarg->rt_dest);
+ /* update proxy seqno to HWMP seqno */
+ rttarg->rt_ext_seq = hs->hs_seq;
+ prep.prep_hopcount = rttarg->rt_nhops;
+ prep.prep_metric = rttarg->rt_metric;
+ IEEE80211_ADDR_COPY(prep.prep_targetaddr, rttarg->rt_mesh_gate);
+ }
+ /*
+ * Build and send a PREP frame.
+ */
prep.prep_ttl = ms->ms_ttl;
- IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
- prep.prep_targetseq = ++hs->hs_seq;
+ prep.prep_targetseq = hs->hs_seq;
prep.prep_lifetime = preq->preq_lifetime;
- prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
prep.prep_origseq = preq->preq_origseq;
- hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
- /*
- * Build the reverse path, if we don't have it already.
- */
- rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
- if (rt == NULL)
- hwmp_discover(vap, preq->preq_origaddr, NULL);
- else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
- hwmp_discover(vap, rt->rt_dest, NULL);
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "reply to %6D", preq->preq_origaddr, ":");
+ hwmp_send_prep(vap, wh->i_addr2, &prep);
return;
}
+ /* we may update our proxy information for the orig external */
+ else if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
+ rtorig_ext =
+ ieee80211_mesh_rt_find(vap, preq->preq_orig_ext_addr);
+ if (rtorig_ext == NULL) {
+ rtorig_ext = ieee80211_mesh_rt_add(vap,
+ preq->preq_orig_ext_addr);
+ if (rtorig_ext == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "unable to add orig ext proxy to %6D",
+ preq->preq_orig_ext_addr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
+ IEEE80211_ADDR_COPY(rtorig_ext->rt_mesh_gate,
+ preq->preq_origaddr);
+ }
+ rtorig_ext->rt_ext_seq = preq->preq_origseq;
+ ieee80211_mesh_rt_update(rtorig_ext, preq->preq_lifetime);
+ }
/*
* Proactive PREQ: reply with a proactive PREP to the
* root STA if requested.
*/
if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
- (PREQ_TFLAGS(0) &
- ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
- (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
- uint8_t rootmac[IEEE80211_ADDR_LEN];
+ (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "root mesh station @ %6D", preq->preq_origaddr, ":");
- IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
- rt = ieee80211_mesh_rt_find(vap, rootmac);
- if (rt == NULL) {
- rt = ieee80211_mesh_rt_add(vap, rootmac);
- if (rt == NULL) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "unable to add root mesh path to %s",
- ether_sprintf(rootmac));
- vap->iv_stats.is_mesh_rtaddfailed++;
- return;
- }
+ /* Check if root is a mesh gate, mark it */
+ if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_GATE) {
+ struct ieee80211_mesh_gate_route *gr;
+
+ rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
+ gr = ieee80211_mesh_mark_gate(vap, preq->preq_origaddr,
+ rtorig);
+ gr->gr_lastseq = 0; /* NOT GANN */
}
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "root mesh station @ %s", ether_sprintf(rootmac));
/*
* Reply with a PREP if we don't have a path to the root
* or if the root sent us a proactive PREQ.
*/
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
+ if ((rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
(preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
prep.prep_flags = 0;
prep.prep_hopcount = 0;
prep.prep_ttl = ms->ms_ttl;
- IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
+ IEEE80211_ADDR_COPY(prep.prep_origaddr,
+ preq->preq_origaddr);
prep.prep_origseq = preq->preq_origseq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
@@ -796,108 +1162,70 @@
IEEE80211_ADDR_COPY(prep.prep_targetaddr,
vap->iv_myaddr);
prep.prep_targetseq = ++hs->hs_seq;
- hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
- broadcastaddr, &prep);
+ hwmp_send_prep(vap, rtorig->rt_nexthop, &prep);
}
- hwmp_discover(vap, rootmac, NULL);
- return;
}
- rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
/*
* Forwarding and Intermediate reply for PREQs with 1 target.
*/
- if (preq->preq_tcount == 1) {
+ if ((preq->preq_tcount == 1) && (preq->preq_ttl > 1) &&
+ (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
memcpy(&ppreq, preq, sizeof(ppreq));
+
/*
* We have a valid route to this node.
+ * NB: if target is proxy dont reply.
*/
- if (rt != NULL &&
- (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
- if (preq->preq_ttl > 1 &&
- preq->preq_hopcount < hs->hs_maxhops) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "forward PREQ from %s",
- ether_sprintf(preq->preq_origaddr));
- /*
- * Propagate the original PREQ.
- */
- ppreq.preq_hopcount += 1;
- ppreq.preq_ttl -= 1;
- ppreq.preq_metric +=
- ms->ms_pmetric->mpm_metric(ni);
- /*
- * Set TO and unset RF bits because we are going
- * to send a PREP next.
- */
- ppreq.preq_targets[0].target_flags |=
- IEEE80211_MESHPREQ_TFLAGS_TO;
- ppreq.preq_targets[0].target_flags &=
- ~IEEE80211_MESHPREQ_TFLAGS_RF;
- hwmp_send_preq(ni, vap->iv_myaddr,
- broadcastaddr, &ppreq);
- }
+ if (rttarg != NULL &&
+ rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
+ !(rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
/*
* Check if we can send an intermediate Path Reply,
- * i.e., Target Only bit is not set.
+ * i.e., Target Only bit is not set and target is not
+ * the MAC broadcast address.
*/
- if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
+ if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO) &&
+ !IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr)) {
struct ieee80211_meshprep_ie prep;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "intermediate reply for PREQ from %s",
- ether_sprintf(preq->preq_origaddr));
+ "intermediate reply for PREQ from %6D",
+ preq->preq_origaddr, ":");
prep.prep_flags = 0;
- prep.prep_hopcount = rt->rt_nhops + 1;
+ prep.prep_hopcount = rttarg->rt_nhops;
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
PREQ_TADDR(0));
- prep.prep_targetseq = hrorig->hr_seq;
+ prep.prep_targetseq = hrtarg->hr_seq;
prep.prep_lifetime = preq->preq_lifetime;
- prep.prep_metric = rt->rt_metric +
- ms->ms_pmetric->mpm_metric(ni);
+ prep.prep_metric =rttarg->rt_metric;
IEEE80211_ADDR_COPY(&prep.prep_origaddr,
preq->preq_origaddr);
prep.prep_origseq = hrorig->hr_seq;
- hwmp_send_prep(ni, vap->iv_myaddr,
- broadcastaddr, &prep);
+ hwmp_send_prep(vap, rtorig->rt_nexthop, &prep);
+
+ /*
+ * Set TO and unset RF bits because we have
+ * sent a PREP.
+ */
+ ppreq.preq_targets[0].target_flags |=
+ IEEE80211_MESHPREQ_TFLAGS_TO;
}
- /*
- * We have no information about this path,
- * propagate the PREQ.
- */
- } else if (preq->preq_ttl > 1 &&
- preq->preq_hopcount < hs->hs_maxhops) {
- if (rt == NULL) {
- rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
- if (rt == NULL) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
- ni, "unable to add PREQ path to %s",
- ether_sprintf(PREQ_TADDR(0)));
- vap->iv_stats.is_mesh_rtaddfailed++;
- return;
- }
- }
- rt->rt_metric = preq->preq_metric;
- rt->rt_lifetime = preq->preq_lifetime;
- hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
- struct ieee80211_hwmp_route);
- hrorig->hr_seq = preq->preq_origseq;
- hrorig->hr_preqid = preq->preq_id;
+ }
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "forward PREQ from %s",
- ether_sprintf(preq->preq_origaddr));
- ppreq.preq_hopcount += 1;
- ppreq.preq_ttl -= 1;
- ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
- hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
- &ppreq);
- }
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "forward PREQ from %6D",
+ preq->preq_origaddr, ":");
+ ppreq.preq_hopcount += 1;
+ ppreq.preq_ttl -= 1;
+ ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
+
+ /* don't do PREQ ratecheck when we propagate */
+ hwmp_send_preq(vap, broadcastaddr, &ppreq, NULL, NULL);
}
-
}
#undef PREQ_TFLAGS
#undef PREQ_TADDR
@@ -904,24 +1232,26 @@
#undef PREQ_TSEQ
static int
-hwmp_send_preq(struct ieee80211_node *ni,
- const uint8_t sa[IEEE80211_ADDR_LEN],
+hwmp_send_preq(struct ieee80211vap *vap,
const uint8_t da[IEEE80211_ADDR_LEN],
- struct ieee80211_meshpreq_ie *preq)
+ struct ieee80211_meshpreq_ie *preq,
+ struct timeval *last, struct timeval *minint)
{
- struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
/*
* Enforce PREQ interval.
+ * NB: Proactive ROOT PREQs rate is handled by cb task.
*/
- if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
- return EALREADY;
- getmicrouptime(&hs->hs_lastpreq);
+ if (last != NULL && minint != NULL) {
+ if (ratecheck(last, minint) == 0)
+ return EALREADY; /* XXX: we should postpone */
+ getmicrouptime(last);
+ }
/*
* mesh preq action frame format
* [6] da
- * [6] sa
+ * [6] sa
* [6] addr3 = sa
* [1] action
* [1] category
@@ -928,8 +1258,10 @@
* [tlv] mesh path request
*/
preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
- return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
- sizeof(struct ieee80211_meshpreq_ie));
+ preq->preq_len = (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE ?
+ IEEE80211_MESHPREQ_BASE_SZ_AE : IEEE80211_MESHPREQ_BASE_SZ) +
+ preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ;
+ return hwmp_send_action(vap, da, (uint8_t *)preq, preq->preq_len+2);
}
static void
@@ -936,127 +1268,180 @@
hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
{
+#define IS_PROXY(rt) (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)
+#define PROXIED_BY_US(rt) \
+ (IEEE80211_ADDR_EQ(vap->iv_myaddr, rt->rt_mesh_gate))
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_mesh_route *rt = NULL;
+ struct ieee80211_mesh_route *rtorig = NULL;
+ struct ieee80211_mesh_route *rtext = NULL;
struct ieee80211_hwmp_route *hr;
struct ieee80211com *ic = vap->iv_ic;
- struct ifnet *ifp = vap->iv_ifp;
struct mbuf *m, *next;
+ uint32_t metric = 0;
+ const uint8_t *addr;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received PREP, orig %6D, targ %6D", prep->prep_origaddr, ":",
+ prep->prep_targetaddr, ":");
+
/*
- * Acceptance criteria: if the corresponding PREQ was not generated
- * by us and forwarding is disabled, discard this PREP.
+ * Acceptance criteria: (If the corresponding PREP was not generated
+ * by us OR not generated by an external mac that is not proxied by us)
+ * AND forwarding is disabled, discard this PREP.
*/
- if (ni == vap->iv_bss ||
- ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
+ rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
+ if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) ||
+ (rtorig != NULL && IS_PROXY(rtorig) && !PROXIED_BY_US(rtorig))) &&
+ !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)){
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "discard PREP, orig(%6D) not proxied or generated by us",
+ prep->prep_origaddr, ":");
return;
- if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
- !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
- return;
+ }
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "received PREP from %s", ether_sprintf(prep->prep_targetaddr));
+ /* PREP ACCEPTED */
+ /*
+ * If accepted shall create or update the active forwarding information
+ * it maintains for the target mesh STA of the PREP (according to the
+ * rules defined in 13.10.8.4). If the conditions for creating or
+ * updating the forwarding information have not been met in those
+ * rules, no further steps are applied to the PREP.
+ */
rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
if (rt == NULL) {
- /*
- * If we have no entry this could be a reply to a root PREQ.
- */
- if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
- rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
- if (rt == NULL) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
- ni, "unable to add PREP path to %s",
- ether_sprintf(prep->prep_targetaddr));
- vap->iv_stats.is_mesh_rtaddfailed++;
- return;
- }
- IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
- rt->rt_nhops = prep->prep_hopcount;
- rt->rt_lifetime = prep->prep_lifetime;
- rt->rt_metric = prep->prep_metric;
- rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
+ rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
+ if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "add root path to %s nhops %d metric %d (PREP)",
- ether_sprintf(prep->prep_targetaddr),
- rt->rt_nhops, rt->rt_metric);
+ "unable to add PREP path to %6D",
+ prep->prep_targetaddr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
return;
- }
- return;
+ }
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "adding target %6D", prep->prep_targetaddr, ":");
}
- /*
- * Sequence number validation.
- */
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP from %s, old seq no %u <= %u",
- ether_sprintf(prep->prep_targetaddr),
- prep->prep_targetseq, hr->hr_seq);
- return;
+ /* update path metric */
+ metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
+ if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "discard PREP from %6D, old seq no %u < %u",
+ prep->prep_targetaddr, ":",
+ prep->prep_targetseq, hr->hr_seq);
+ return;
+ } else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) &&
+ metric > rt->rt_metric) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "discard PREP from %6D, new metric %u > %u",
+ prep->prep_targetaddr, ":",
+ metric, rt->rt_metric);
+ return;
+ }
}
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "%s path to %6D, hopcount %d:%d metric %d:%d",
+ rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+ "prefer" : "update",
+ prep->prep_targetaddr, ":",
+ rt->rt_nhops, prep->prep_hopcount + 1,
+ rt->rt_metric, metric);
+
hr->hr_seq = prep->prep_targetseq;
+ hr->hr_preqretries = 0;
+ IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr);
+ rt->rt_metric = metric;
+ rt->rt_nhops = prep->prep_hopcount + 1;
+ ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) {
+ /* discovery complete */
+ rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_DISCOVER;
+ }
+ rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */
+
+ /* Update forwarding information to TA if metric improves */
+ hwmp_update_transmitter(vap, ni, "PREP");
+
/*
- * If it's NOT for us, propagate the PREP.
+ * If it's NOT for us, propagate the PREP
*/
if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
- prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
+ prep->prep_ttl > 1 &&
+ prep->prep_hopcount < hs->hs_maxhops) {
struct ieee80211_meshprep_ie pprep; /* propagated PREP */
+ /*
+ * NB: We should already have setup the path to orig
+ * mesh STA when we propagated PREQ to target mesh STA,
+ * no PREP is generated without a corresponding PREQ.
+ * XXX: for now just ignore.
+ */
+ if (rtorig == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received PREP for an unknown orig(%6D)",
+ prep->prep_origaddr, ":");
+ return;
+ }
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "propagate PREP from %s",
- ether_sprintf(prep->prep_targetaddr));
+ "propagate PREP from %6D",
+ prep->prep_targetaddr, ":");
memcpy(&pprep, prep, sizeof(pprep));
pprep.prep_hopcount += 1;
pprep.prep_ttl -= 1;
pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
- IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
- hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
+ hwmp_send_prep(vap, rtorig->rt_nexthop, &pprep);
+
+ /* precursor list for the Target Mesh STA Address is updated */
}
- hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
- /* NB: never clobber a proxy entry */;
+
+ /*
+ * Check if we received a PREP w/ AE and store target external address.
+ * We may store target external address if recevied PREP w/ AE
+ * and we are not final destination
+ */
+ if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
+ rtext = ieee80211_mesh_rt_find(vap,
+ prep->prep_target_ext_addr);
+ if (rtext == NULL) {
+ rtext = ieee80211_mesh_rt_add(vap,
+ prep->prep_target_ext_addr);
+ if (rtext == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "unable to add PREP path to proxy %6D",
+ prep->prep_targetaddr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
+ }
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP for %s, route is marked PROXY",
- ether_sprintf(prep->prep_targetaddr));
- vap->iv_stats.is_hwmp_proxy++;
- } else if (prep->prep_origseq == hr->hr_origseq) {
+ "%s path to %6D, hopcount %d:%d metric %d:%d",
+ rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+ "prefer" : "update",
+ prep->prep_target_ext_addr, ":",
+ rtext->rt_nhops, prep->prep_hopcount + 1,
+ rtext->rt_metric, metric);
+
+ rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
+ IEEE80211_MESHRT_FLAGS_VALID;
+ IEEE80211_ADDR_COPY(rtext->rt_dest,
+ prep->prep_target_ext_addr);
+ IEEE80211_ADDR_COPY(rtext->rt_mesh_gate,
+ prep->prep_targetaddr);
+ IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2);
+ rtext->rt_metric = metric;
+ rtext->rt_lifetime = prep->prep_lifetime;
+ rtext->rt_nhops = prep->prep_hopcount + 1;
+ rtext->rt_ext_seq = prep->prep_origseq; /* new proxy seq */
/*
- * Check if we already have a path to this node.
- * If we do, check if this path reply contains a
- * better route.
+ * XXX: proxy entries have no HWMP priv data,
+ * nullify them to be sure?
*/
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
- (prep->prep_hopcount < rt->rt_nhops ||
- prep->prep_metric < rt->rt_metric)) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "%s path to %s, hopcount %d:%d metric %d:%d",
- rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
- "prefer" : "update",
- ether_sprintf(prep->prep_origaddr),
- rt->rt_nhops, prep->prep_hopcount,
- rt->rt_metric, prep->prep_metric);
- IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
- rt->rt_nhops = prep->prep_hopcount;
- rt->rt_lifetime = prep->prep_lifetime;
- rt->rt_metric = prep->prep_metric;
- rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
- } else {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "ignore PREP for %s, hopcount %d:%d metric %d:%d",
- ether_sprintf(prep->prep_targetaddr),
- rt->rt_nhops, prep->prep_hopcount,
- rt->rt_metric, prep->prep_metric);
- }
- } else {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP for %s, wrong seqno %u != %u",
- ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
- hr->hr_seq);
- vap->iv_stats.is_hwmp_wrongseq++;
- }
+ }
/*
* Check for frames queued awaiting path discovery.
* XXX probably can tell exactly and avoid remove call
@@ -1064,21 +1449,33 @@
* stuck back on the stageq because there won't be
* a path.
*/
- m = ieee80211_ageq_remove(&ic->ic_stageq,
+ addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
+ prep->prep_target_ext_addr : prep->prep_targetaddr;
+ m = ieee80211_ageq_remove(&ic->ic_stageq,
(struct ieee80211_node *)(uintptr_t)
- ieee80211_mac_hash(ic, rt->rt_dest));
+ ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */
+
+ /*
+ * All frames in the stageq here should be non-M_ENCAP; or things
+ * will get very unhappy.
+ */
for (; m != NULL; m = next) {
next = m->m_nextpkt;
m->m_nextpkt = NULL;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"flush queued frame %p len %d", m, m->m_pkthdr.len);
- ifp->if_transmit(ifp, m);
+ /*
+ * If the mbuf has M_ENCAP set, ensure we free it.
+ * Note that after if_transmit() is called, m is invalid.
+ */
+ (void) ieee80211_vap_xmitpkt(vap, m);
}
+#undef IS_PROXY
+#undef PROXIED_BY_US
}
static int
-hwmp_send_prep(struct ieee80211_node *ni,
- const uint8_t sa[IEEE80211_ADDR_LEN],
+hwmp_send_prep(struct ieee80211vap *vap,
const uint8_t da[IEEE80211_ADDR_LEN],
struct ieee80211_meshprep_ie *prep)
{
@@ -1087,7 +1484,7 @@
/*
* mesh prep action frame format
* [6] da
- * [6] sa
+ * [6] sa
* [6] addr3 = sa
* [1] action
* [1] category
@@ -1094,8 +1491,9 @@
* [tlv] mesh path reply
*/
prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
- return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
- sizeof(struct ieee80211_meshprep_ie));
+ prep->prep_len = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
+ IEEE80211_MESHPREP_BASE_SZ_AE : IEEE80211_MESHPREP_BASE_SZ;
+ return hwmp_send_action(vap, da, (uint8_t *)prep, prep->prep_len + 2);
}
#define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags
@@ -1124,11 +1522,11 @@
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
- PERR_DSEQ(0) = hr->hr_seq;
+ PERR_DSEQ(0) = ++hr->hr_seq;
PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
/* NB: flush everything passing through peer */
ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
- hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
+ hwmp_send_perr(vap, broadcastaddr, &perr);
}
#undef PERR_DFLAGS
#undef PERR_DADDR
@@ -1135,10 +1533,11 @@
#undef PERR_DSEQ
#undef PERR_DRCODE
-#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
-#define PERR_DADDR(n) perr->perr_dests[n].dest_addr
-#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
-#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
+#define PERR_DFLAGS(n) perr->perr_dests[n].dest_flags
+#define PERR_DADDR(n) perr->perr_dests[n].dest_addr
+#define PERR_DSEQ(n) perr->perr_dests[n].dest_seq
+#define PERR_DEXTADDR(n) perr->perr_dests[n].dest_ext_addr
+#define PERR_DRCODE(n) perr->perr_dests[n].dest_rcode
static void
hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
const struct ieee80211_frame *wh, const struct ieee80211_meshperr_ie *perr)
@@ -1145,57 +1544,111 @@
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt = NULL;
+ struct ieee80211_mesh_route *rt_ext = NULL;
struct ieee80211_hwmp_route *hr;
- struct ieee80211_meshperr_ie pperr;
- int i, forward = 0;
+ struct ieee80211_meshperr_ie *pperr = NULL;
+ int i, j = 0, forward = 0;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received PERR from %6D", wh->i_addr2, ":");
+
/*
- * Acceptance criteria: check if we received a PERR from a
- * neighbor and forwarding is enabled.
+ * if forwarding is true, prepare pperr
*/
- if (ni == vap->iv_bss ||
- ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
- !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
- return;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) {
+ forward = 1;
+ pperr = malloc(sizeof(*perr) + 31*sizeof(*perr->perr_dests),
+ M_80211_MESH_PERR, M_NOWAIT); /* XXX: magic number, 32 err dests */
+ }
+
/*
- * Find all routing entries that match and delete them.
+ * Acceptance criteria: check if we have forwarding information
+ * stored about destination, and that nexthop == TA of this PERR.
+ * NB: we also build a new PERR to propagate in case we should forward.
*/
for (i = 0; i < perr->perr_ndests; i++) {
rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
if (rt == NULL)
continue;
+ if (!IEEE80211_ADDR_EQ(rt->rt_nexthop, wh->i_addr2))
+ continue;
+
+ /* found and accepted a PERR ndest element, process it... */
+ if (forward)
+ memcpy(&pperr->perr_dests[j], &perr->perr_dests[i],
+ sizeof(*perr->perr_dests));
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) &&
- HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
- ieee80211_mesh_rt_del(vap, rt->rt_dest);
- ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
- rt = NULL;
- forward = 1;
+ switch(PERR_DFLAGS(i)) {
+ case (IEEE80211_REASON_MESH_PERR_NO_FI):
+ if (PERR_DSEQ(i) == 0) {
+ hr->hr_seq++;
+ if (forward) {
+ pperr->perr_dests[j].dest_seq =
+ hr->hr_seq;
+ }
+ } else {
+ hr->hr_seq = PERR_DSEQ(i);
+ }
+ rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
+ j++;
+ break;
+ case (IEEE80211_REASON_MESH_PERR_DEST_UNREACH):
+ if(HWMP_SEQ_GT(PERR_DSEQ(i), hr->hr_seq)) {
+ hr->hr_seq = PERR_DSEQ(i);
+ rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
+ j++;
+ }
+ break;
+ case (IEEE80211_REASON_MESH_PERR_NO_PROXY):
+ rt_ext = ieee80211_mesh_rt_find(vap, PERR_DEXTADDR(i));
+ if (rt_ext != NULL) {
+ rt_ext->rt_flags &=
+ ~IEEE80211_MESHRT_FLAGS_VALID;
+ j++;
+ }
+ break;
+ default:
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
+ "PERR, unknown reason code %u\n", PERR_DFLAGS(i));
+ goto done; /* XXX: stats?? */
}
+ ieee80211_mesh_rt_flush_peer(vap, PERR_DADDR(i));
+ KASSERT(j < 32, ("PERR, error ndest >= 32 (%u)", j));
}
+ if (j == 0) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL, "%s",
+ "PERR not accepted");
+ goto done; /* XXX: stats?? */
+ }
+
/*
* Propagate the PERR if we previously found it on our routing table.
- * XXX handle ndest > 1
*/
if (forward && perr->perr_ttl > 1) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "propagate PERR from %s", ether_sprintf(wh->i_addr2));
- memcpy(&pperr, perr, sizeof(*perr));
- pperr.perr_ttl--;
- hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
- &pperr);
+ "propagate PERR from %6D", wh->i_addr2, ":");
+ pperr->perr_ndests = j;
+ pperr->perr_ttl--;
+ hwmp_send_perr(vap, broadcastaddr, pperr);
}
+done:
+ if (pperr != NULL)
+ free(pperr, M_80211_MESH_PERR);
}
-#undef PEER_DADDR
+#undef PERR_DFLAGS
+#undef PERR_DADDR
#undef PERR_DSEQ
+#undef PERR_DEXTADDR
+#undef PERR_DRCODE
static int
-hwmp_send_perr(struct ieee80211_node *ni,
- const uint8_t sa[IEEE80211_ADDR_LEN],
+hwmp_send_perr(struct ieee80211vap *vap,
const uint8_t da[IEEE80211_ADDR_LEN],
struct ieee80211_meshperr_ie *perr)
{
- struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
+ struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
+ int i;
+ uint8_t length = 0;
/*
* Enforce PERR interval.
@@ -1214,11 +1667,78 @@
* [tlv] mesh path error
*/
perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
- return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
- sizeof(struct ieee80211_meshperr_ie));
+ length = IEEE80211_MESHPERR_BASE_SZ;
+ for (i = 0; i<perr->perr_ndests; i++) {
+ if (perr->perr_dests[i].dest_flags &
+ IEEE80211_MESHPERR_FLAGS_AE) {
+ length += IEEE80211_MESHPERR_DEST_SZ_AE;
+ continue ;
+ }
+ length += IEEE80211_MESHPERR_DEST_SZ;
+ }
+ perr->perr_len =length;
+ return hwmp_send_action(vap, da, (uint8_t *)perr, perr->perr_len+2);
}
+/*
+ * Called from the rest of the net80211 code (mesh code for example).
+ * NB: IEEE80211_REASON_MESH_PERR_DEST_UNREACH can be trigger by the fact that
+ * a mesh STA is unable to forward an MSDU/MMPDU to a next-hop mesh STA.
+ */
+#define PERR_DFLAGS(n) perr.perr_dests[n].dest_flags
+#define PERR_DADDR(n) perr.perr_dests[n].dest_addr
+#define PERR_DSEQ(n) perr.perr_dests[n].dest_seq
+#define PERR_DEXTADDR(n) perr.perr_dests[n].dest_ext_addr
+#define PERR_DRCODE(n) perr.perr_dests[n].dest_rcode
static void
+hwmp_senderror(struct ieee80211vap *vap,
+ const uint8_t addr[IEEE80211_ADDR_LEN],
+ struct ieee80211_mesh_route *rt, int rcode)
+{
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_hwmp_route *hr = NULL;
+ struct ieee80211_meshperr_ie perr;
+
+ if (rt != NULL)
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt,
+ struct ieee80211_hwmp_route);
+
+ perr.perr_ndests = 1;
+ perr.perr_ttl = ms->ms_ttl;
+ PERR_DFLAGS(0) = 0;
+ PERR_DRCODE(0) = rcode;
+
+ switch (rcode) {
+ case IEEE80211_REASON_MESH_PERR_NO_FI:
+ IEEE80211_ADDR_COPY(PERR_DADDR(0), addr);
+ PERR_DSEQ(0) = 0; /* reserved */
+ break;
+ case IEEE80211_REASON_MESH_PERR_NO_PROXY:
+ KASSERT(rt != NULL, ("no proxy info for sending PERR"));
+ KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
+ ("route is not marked proxy"));
+ PERR_DFLAGS(0) |= IEEE80211_MESHPERR_FLAGS_AE;
+ IEEE80211_ADDR_COPY(PERR_DADDR(0), vap->iv_myaddr);
+ PERR_DSEQ(0) = rt->rt_ext_seq;
+ IEEE80211_ADDR_COPY(PERR_DEXTADDR(0), addr);
+ break;
+ case IEEE80211_REASON_MESH_PERR_DEST_UNREACH:
+ KASSERT(rt != NULL, ("no route info for sending PERR"));
+ IEEE80211_ADDR_COPY(PERR_DADDR(0), addr);
+ PERR_DSEQ(0) = hr->hr_seq;
+ break;
+ default:
+ KASSERT(0, ("unknown reason code for HWMP PERR (%u)", rcode));
+ }
+ hwmp_send_perr(vap, broadcastaddr, &perr);
+}
+#undef PERR_DFLAGS
+#undef PEER_DADDR
+#undef PERR_DSEQ
+#undef PERR_DEXTADDR
+#undef PERR_DRCODE
+
+static void
hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
{
@@ -1226,41 +1746,95 @@
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_mesh_route *rt = NULL;
struct ieee80211_hwmp_route *hr;
+ struct ieee80211_meshpreq_ie preq;
struct ieee80211_meshrann_ie prann;
+ uint32_t metric = 0;
- if (ni == vap->iv_bss ||
- ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
- IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
+ if (IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
return;
rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
- /*
- * Discover the path to the root mesh STA.
- * If we already know it, propagate the RANN element.
- */
+ if (rt != NULL && rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) {
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+
+ /* Acceptance criteria: if RANN.seq < stored seq, discard RANN */
+ if (HWMP_SEQ_LT(rann->rann_seq, hr->hr_seq)) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
+ "RANN seq %u < %u", rann->rann_seq, hr->hr_seq);
+ return;
+ }
+
+ /* Acceptance criteria: if RANN.seq == stored seq AND
+ * RANN.metric > stored metric, discard RANN */
+ if (HWMP_SEQ_EQ(rann->rann_seq, hr->hr_seq) &&
+ rann->rann_metric > rt->rt_metric) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
+ "RANN metric %u > %u", rann->rann_metric, rt->rt_metric);
+ return;
+ }
+ }
+
+ /* RANN ACCEPTED */
+
+ ieee80211_hwmp_rannint = rann->rann_interval; /* XXX: mtx lock? */
+ metric = rann->rann_metric + ms->ms_pmetric->mpm_metric(ni);
+
if (rt == NULL) {
- hwmp_discover(vap, rann->rann_addr, NULL);
- return;
+ rt = ieee80211_mesh_rt_add(vap, rann->rann_addr);
+ if (rt == NULL) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_HWMP, wh, NULL,
+ "unable to add mac for RANN root %6D",
+ rann->rann_addr, ":");
+ vap->iv_stats.is_mesh_rtaddfailed++;
+ return;
+ }
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
+ /* Check if root is a mesh gate, mark it */
+ if (rann->rann_flags & IEEE80211_MESHRANN_FLAGS_GATE) {
+ struct ieee80211_mesh_gate_route *gr;
+
+ rt->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
+ gr = ieee80211_mesh_mark_gate(vap, rann->rann_addr,
+ rt);
+ gr->gr_lastseq = 0; /* NOT GANN */
+ }
+ /* discovery timeout */
+ ieee80211_mesh_rt_update(rt,
+ ticks_to_msecs(ieee80211_hwmp_roottimeout));
+
+ preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
+ preq.preq_hopcount = 0;
+ preq.preq_ttl = ms->ms_ttl;
+ preq.preq_id = 0; /* reserved */
+ IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
+ preq.preq_origseq = ++hs->hs_seq;
+ preq.preq_lifetime = ieee80211_hwmp_roottimeout;
+ preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
+ preq.preq_tcount = 1;
+ preq.preq_targets[0].target_flags = IEEE80211_MESHPREQ_TFLAGS_TO;
+ /* NB: IEEE80211_MESHPREQ_TFLAGS_USN = 0 implicitly implied */
+ IEEE80211_ADDR_COPY(preq.preq_targets[0].target_addr, rann->rann_addr);
+ preq.preq_targets[0].target_seq = rann->rann_seq;
+ /* XXX: if rootconfint have not passed, we built this preq in vain */
+ hwmp_send_preq(vap, wh->i_addr2, &preq, &hr->hr_lastrootconf,
+ &ieee80211_hwmp_rootconfint);
+
+ /* propagate a RANN */
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID &&
+ rann->rann_ttl > 1 &&
+ ms->ms_flags & IEEE80211_MESHFLAGS_FWD) {
hr->hr_seq = rann->rann_seq;
- if (rann->rann_ttl > 1 &&
- rann->rann_hopcount < hs->hs_maxhops &&
- (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
- memcpy(&prann, rann, sizeof(prann));
- prann.rann_hopcount += 1;
- prann.rann_ttl -= 1;
- prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
- hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
- broadcastaddr, &prann);
- }
+ memcpy(&prann, rann, sizeof(prann));
+ prann.rann_hopcount += 1;
+ prann.rann_ttl -= 1;
+ prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
+ hwmp_send_rann(vap, broadcastaddr, &prann);
}
}
static int
-hwmp_send_rann(struct ieee80211_node *ni,
- const uint8_t sa[IEEE80211_ADDR_LEN],
+hwmp_send_rann(struct ieee80211vap *vap,
const uint8_t da[IEEE80211_ADDR_LEN],
struct ieee80211_meshrann_ie *rann)
{
@@ -1267,7 +1841,7 @@
/*
* mesh rann action frame format
* [6] da
- * [6] sa
+ * [6] sa
* [6] addr3 = sa
* [1] action
* [1] category
@@ -1274,13 +1848,69 @@
* [tlv] root annoucement
*/
rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
- return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
- sizeof(struct ieee80211_meshrann_ie));
+ rann->rann_len = IEEE80211_MESHRANN_BASE_SZ;
+ return hwmp_send_action(vap, da, (uint8_t *)rann, rann->rann_len + 2);
}
#define PREQ_TFLAGS(n) preq.preq_targets[n].target_flags
#define PREQ_TADDR(n) preq.preq_targets[n].target_addr
#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq
+static void
+hwmp_rediscover_cb(void *arg)
+{
+ struct ieee80211_mesh_route *rt = arg;
+ struct ieee80211vap *vap = rt->rt_vap;
+ struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_hwmp_route *hr;
+ struct ieee80211_meshpreq_ie preq; /* Optimize: storing first preq? */
+
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID))
+ return ; /* nothing to do */
+
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+ if (hr->hr_preqretries >=
+ ieee80211_hwmp_maxpreq_retries) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ANY,
+ rt->rt_dest, "%s",
+ "max number of discovery, send queued frames to GATE");
+ ieee80211_mesh_forward_to_gates(vap, rt);
+ vap->iv_stats.is_mesh_fwd_nopath++;
+ return ; /* XXX: flush queue? */
+ }
+
+ hr->hr_preqretries++;
+
+
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, rt->rt_dest,
+ "start path rediscovery , target seq %u", hr->hr_seq);
+ /*
+ * Try to discover the path for this node.
+ * Group addressed PREQ Case A
+ */
+ preq.preq_flags = 0;
+ preq.preq_hopcount = 0;
+ preq.preq_ttl = ms->ms_ttl;
+ preq.preq_id = ++hs->hs_preqid;
+ IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
+ preq.preq_origseq = hr->hr_origseq;
+ preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_pathtimeout);
+ preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
+ preq.preq_tcount = 1;
+ IEEE80211_ADDR_COPY(PREQ_TADDR(0), rt->rt_dest);
+ PREQ_TFLAGS(0) = 0;
+ if (ieee80211_hwmp_targetonly)
+ PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
+ PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
+ PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
+ /* XXX check return value */
+ hwmp_send_preq(vap, broadcastaddr, &preq, &hr->hr_lastpreq,
+ &ieee80211_hwmp_preqminint);
+ callout_reset(&rt->rt_discovery,
+ ieee80211_hwmp_net_diameter_traversaltime * 2,
+ hwmp_rediscover_cb, rt);
+}
+
static struct ieee80211_node *
hwmp_discover(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
@@ -1306,8 +1936,8 @@
rt = ieee80211_mesh_rt_add(vap, dest);
if (rt == NULL) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
- ni, "unable to add discovery path to %s",
- ether_sprintf(dest));
+ ni, "unable to add discovery path to %6D",
+ dest, ":");
vap->iv_stats.is_mesh_rtaddfailed++;
goto done;
}
@@ -1314,20 +1944,45 @@
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route);
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
+ "%s", "already discovering queue frame until path found");
+ sendpreq = 1;
+ goto done;
+ }
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+ if (hr->hr_lastdiscovery != 0 &&
+ (ticks - hr->hr_lastdiscovery <
+ (ieee80211_hwmp_net_diameter_traversaltime * 2))) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+ dest, NULL, "%s",
+ "too frequent discovery requeust");
+ sendpreq = 1;
+ goto done;
+ }
+ hr->hr_lastdiscovery = ticks;
+ if (hr->hr_preqretries >=
+ ieee80211_hwmp_maxpreq_retries) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+ dest, NULL, "%s",
+ "no valid path , max number of discovery");
+ vap->iv_stats.is_mesh_fwd_nopath++;
+ goto done;
+ }
+ rt->rt_flags = IEEE80211_MESHRT_FLAGS_DISCOVER;
+ hr->hr_preqretries++;
if (hr->hr_origseq == 0)
hr->hr_origseq = ++hs->hs_seq;
rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
- rt->rt_lifetime =
- ticks_to_msecs(ieee80211_hwmp_pathtimeout);
- /* XXX check preq retries */
sendpreq = 1;
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
- "start path discovery (src %s)",
+ "start path discovery (src %s), target seq %u",
m == NULL ? "<none>" : ether_sprintf(
- mtod(m, struct ether_header *)->ether_shost));
+ mtod(m, struct ether_header *)->ether_shost),
+ hr->hr_seq);
/*
* Try to discover the path for this node.
+ * Group addressed PREQ Case A
*/
preq.preq_flags = 0;
preq.preq_hopcount = 0;
@@ -1335,20 +1990,22 @@
preq.preq_id = ++hs->hs_preqid;
IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
preq.preq_origseq = hr->hr_origseq;
- preq.preq_lifetime = rt->rt_lifetime;
- preq.preq_metric = rt->rt_metric;
+ preq.preq_lifetime =
+ ticks_to_msecs(ieee80211_hwmp_pathtimeout);
+ preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
preq.preq_tcount = 1;
IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
PREQ_TFLAGS(0) = 0;
if (ieee80211_hwmp_targetonly)
PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
- if (ieee80211_hwmp_replyforward)
- PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
- PREQ_TSEQ(0) = 0;
+ PREQ_TSEQ(0) = 0; /* RESERVED when USN flag is set */
/* XXX check return value */
- hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
- broadcastaddr, &preq);
+ hwmp_send_preq(vap, broadcastaddr, &preq,
+ &hr->hr_lastpreq, &ieee80211_hwmp_preqminint);
+ callout_reset(&rt->rt_discovery,
+ ieee80211_hwmp_net_diameter_traversaltime * 2,
+ hwmp_rediscover_cb, rt);
}
if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
@@ -1391,7 +2048,7 @@
{
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
int error;
-
+
if (vap->iv_opmode != IEEE80211_M_MBSS)
return ENOSYS;
error = 0;
Modified: trunk/sys/net80211/ieee80211_input.c
===================================================================
--- trunk/sys/net80211/ieee80211_input.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_input.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_input.c 254640 2013-08-22 05:53:47Z adrian $");
#include "opt_wlan.h"
@@ -131,7 +132,7 @@
* Packet contents are changed by ieee80211_decap
* so do a deep copy of the packet.
*/
- mcopy = m_dup(m, M_DONTWAIT);
+ mcopy = m_dup(m, M_NOWAIT);
if (mcopy == NULL) {
/* XXX stat+msg */
continue;
@@ -250,7 +251,10 @@
struct ifnet *ifp = vap->iv_ifp;
/* clear driver/net80211 flags before passing up */
- m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
+ m->m_flags &= ~(M_MCAST | M_BCAST);
+#if __FreeBSD_version >= 1000046
+ m_clrprotoflags(m);
+#endif
/* NB: see hostap_deliver_data, this path doesn't handle hostap */
KASSERT(vap->iv_opmode != IEEE80211_M_HOSTAP, ("gack, hostap"));
@@ -323,13 +327,13 @@
IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr4);
break;
}
-#ifdef ALIGNED_POINTER
+#ifndef __NO_STRICT_ALIGNMENT
if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
m = ieee80211_realign(vap, m, sizeof(*eh));
if (m == NULL)
return NULL;
}
-#endif /* ALIGNED_POINTER */
+#endif /* !__NO_STRICT_ALIGNMENT */
if (llc != NULL) {
eh = mtod(m, struct ether_header *);
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
@@ -522,6 +526,9 @@
case IEEE80211_ELEMID_CSA:
scan->csa = frm;
break;
+ case IEEE80211_ELEMID_QUIET:
+ scan->quiet = frm;
+ break;
case IEEE80211_ELEMID_FHPARMS:
if (ic->ic_phytype == IEEE80211_T_FH) {
scan->fhdwell = LE_READ_2(&frm[2]);
@@ -649,7 +656,8 @@
scan->bintval <= IEEE80211_BINTVAL_MAX)) {
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
- wh, NULL, "bogus beacon interval", scan->bintval);
+ wh, NULL, "bogus beacon interval (%d TU)",
+ (int) scan->bintval);
vap->iv_stats.is_rx_badbintval++;
scan->status |= IEEE80211_BPARSE_BINTVAL_INVALID;
}
@@ -756,6 +764,61 @@
break;
}
break;
+#ifdef IEEE80211_SUPPORT_MESH
+ case IEEE80211_ACTION_CAT_MESH:
+ switch (ia->ia_action) {
+ case IEEE80211_ACTION_MESH_LMETRIC:
+ /*
+ * XXX: verification is true only if we are using
+ * Airtime link metric (default)
+ */
+ IEEE80211_VERIFY_LENGTH(efrm - frm,
+ sizeof(struct ieee80211_meshlmetric_ie),
+ return EINVAL);
+ break;
+ case IEEE80211_ACTION_MESH_HWMP:
+ /* verify something */
+ break;
+ case IEEE80211_ACTION_MESH_GANN:
+ IEEE80211_VERIFY_LENGTH(efrm - frm,
+ sizeof(struct ieee80211_meshgann_ie),
+ return EINVAL);
+ break;
+ case IEEE80211_ACTION_MESH_CC:
+ case IEEE80211_ACTION_MESH_MCCA_SREQ:
+ case IEEE80211_ACTION_MESH_MCCA_SREP:
+ case IEEE80211_ACTION_MESH_MCCA_AREQ:
+ case IEEE80211_ACTION_MESH_MCCA_ADVER:
+ case IEEE80211_ACTION_MESH_MCCA_TRDOWN:
+ case IEEE80211_ACTION_MESH_TBTT_REQ:
+ case IEEE80211_ACTION_MESH_TBTT_RES:
+ /* reject these early on, not implemented */
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
+ wh, NULL, "not implemented yet, act=0x%02X",
+ ia->ia_action);
+ return EINVAL;
+ }
+ break;
+ case IEEE80211_ACTION_CAT_SELF_PROT:
+ /* If TA or RA group address discard silently */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ IEEE80211_IS_MULTICAST(wh->i_addr2))
+ return EINVAL;
+ /*
+ * XXX: Should we verify complete length now or it is
+ * to varying in sizes?
+ */
+ switch (ia->ia_action) {
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ case IEEE80211_ACTION_MESHPEERING_CLOSE:
+ /* is not a peering candidate (yet) */
+ if (ni == vap->iv_bss)
+ return EINVAL;
+ break;
+ }
+ break;
+#endif
}
return 0;
}
Modified: trunk/sys/net80211/ieee80211_input.h
===================================================================
--- trunk/sys/net80211/ieee80211_input.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_input.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_input.h 221418 2011-05-04 02:23:59Z adrian $
*/
#ifndef _NET80211_IEEE80211_INPUT_H_
#define _NET80211_IEEE80211_INPUT_H_
Modified: trunk/sys/net80211/ieee80211_ioctl.c
===================================================================
--- trunk/sys/net80211/ieee80211_ioctl.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ioctl.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ioctl.c 322061 2017-08-04 20:24:23Z pfg $");
/*
* IEEE 802.11 ioctl support (FreeBSD-specific)
@@ -972,6 +973,21 @@
case IEEE80211_IOC_PUREG:
ireq->i_val = (vap->iv_flags & IEEE80211_F_PUREG) != 0;
break;
+ case IEEE80211_IOC_QUIET:
+ ireq->i_val = vap->iv_quiet;
+ break;
+ case IEEE80211_IOC_QUIET_COUNT:
+ ireq->i_val = vap->iv_quiet_count;
+ break;
+ case IEEE80211_IOC_QUIET_PERIOD:
+ ireq->i_val = vap->iv_quiet_period;
+ break;
+ case IEEE80211_IOC_QUIET_DUR:
+ ireq->i_val = vap->iv_quiet_duration;
+ break;
+ case IEEE80211_IOC_QUIET_OFFSET:
+ ireq->i_val = vap->iv_quiet_offset;
+ break;
case IEEE80211_IOC_BGSCAN:
ireq->i_val = (vap->iv_flags & IEEE80211_F_BGSCAN) != 0;
break;
@@ -1325,12 +1341,17 @@
if (!IEEE80211_ADDR_EQ(mac, ic->ic_ifp->if_broadcastaddr)) {
IEEE80211_NODE_LOCK(nt);
ni = ieee80211_find_node_locked(nt, mac);
+ IEEE80211_NODE_UNLOCK(nt);
+ /*
+ * Don't do the node update inside the node
+ * table lock. This unfortunately causes LORs
+ * with drivers and their TX paths.
+ */
if (ni != NULL) {
domlme(mlmeop, ni);
ieee80211_free_node(ni);
} else
error = ENOENT;
- IEEE80211_NODE_UNLOCK(nt);
} else {
ieee80211_iterate_nodes(nt, domlme, mlmeop);
}
@@ -1382,6 +1403,22 @@
IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
ieee80211_free_node(ni);
break;
+ case IEEE80211_M_MBSS:
+ IEEE80211_NODE_LOCK(nt);
+ ni = ieee80211_find_node_locked(nt, mac);
+ /*
+ * Don't do the node update inside the node
+ * table lock. This unfortunately causes LORs
+ * with drivers and their TX paths.
+ */
+ IEEE80211_NODE_UNLOCK(nt);
+ if (ni != NULL) {
+ ieee80211_node_leave(ni);
+ ieee80211_free_node(ni);
+ } else {
+ error = ENOENT;
+ }
+ break;
default:
error = EINVAL;
break;
@@ -1396,6 +1433,12 @@
}
IEEE80211_NODE_LOCK(nt);
ni = ieee80211_find_vap_node_locked(nt, vap, mac);
+ /*
+ * Don't do the node update inside the node
+ * table lock. This unfortunately causes LORs
+ * with drivers and their TX paths.
+ */
+ IEEE80211_NODE_UNLOCK(nt);
if (ni != NULL) {
mlmedebug(vap, mac, op, reason);
if (op == IEEE80211_MLME_AUTHORIZE)
@@ -1405,7 +1448,6 @@
ieee80211_free_node(ni);
} else
error = ENOENT;
- IEEE80211_NODE_UNLOCK(nt);
break;
case IEEE80211_MLME_AUTH:
if (vap->iv_opmode != IEEE80211_M_HOSTAP) {
@@ -1414,6 +1456,12 @@
}
IEEE80211_NODE_LOCK(nt);
ni = ieee80211_find_vap_node_locked(nt, vap, mac);
+ /*
+ * Don't do the node update inside the node
+ * table lock. This unfortunately causes LORs
+ * with drivers and their TX paths.
+ */
+ IEEE80211_NODE_UNLOCK(nt);
if (ni != NULL) {
mlmedebug(vap, mac, op, reason);
if (reason == IEEE80211_STATUS_SUCCESS) {
@@ -1437,7 +1485,6 @@
ieee80211_free_node(ni);
} else
error = ENOENT;
- IEEE80211_NODE_UNLOCK(nt);
break;
default:
error = EINVAL;
@@ -1543,7 +1590,9 @@
mlme.im_op == IEEE80211_MLME_ASSOC)
return setmlme_assoc_sta(vap, mlme.im_macaddr,
vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid);
- else if (mlme.im_op == IEEE80211_MLME_ASSOC)
+ else if ((vap->iv_opmode == IEEE80211_M_IBSS ||
+ vap->iv_opmode == IEEE80211_M_AHDEMO) &&
+ mlme.im_op == IEEE80211_MLME_ASSOC)
return setmlme_assoc_adhoc(vap, mlme.im_macaddr,
mlme.im_ssid_len, mlme.im_ssid);
else
@@ -1922,9 +1971,10 @@
/* XXX need state machine for other vap's to follow */
ieee80211_setcurchan(ic, vap->iv_des_chan);
vap->iv_bss->ni_chan = ic->ic_curchan;
- } else
+ } else {
ic->ic_curchan = vap->iv_des_chan;
ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);
+ }
} else {
/*
* Need to go through the state machine in case we
@@ -2939,6 +2989,24 @@
if (isvap11g(vap))
error = ENETRESET;
break;
+ case IEEE80211_IOC_QUIET:
+ vap->iv_quiet= ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_COUNT:
+ vap->iv_quiet_count=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_PERIOD:
+ vap->iv_quiet_period=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_OFFSET:
+ vap->iv_quiet_offset=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_DUR:
+ if(ireq->i_val < vap->iv_bss->ni_intval)
+ vap->iv_quiet_duration = ireq->i_val;
+ else
+ error = EINVAL;
+ break;
case IEEE80211_IOC_BGSCAN:
if (ireq->i_val) {
if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0)
Modified: trunk/sys/net80211/ieee80211_ioctl.h
===================================================================
--- trunk/sys/net80211/ieee80211_ioctl.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ioctl.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_ioctl.h 246501 2013-02-07 21:20:28Z monthadar $
*/
#ifndef _NET80211_IEEE80211_IOCTL_H_
#define _NET80211_IEEE80211_IOCTL_H_
@@ -241,8 +242,12 @@
uint32_t is_mesh_notproxy; /* dropped 'cuz not proxying */
uint32_t is_rx_badalign; /* dropped 'cuz misaligned */
uint32_t is_hwmp_proxy; /* PREP for proxy route */
-
- uint32_t is_spare[11];
+ uint32_t is_beacon_bad; /* Number of bad beacons */
+ uint32_t is_ampdu_bar_tx; /* A-MPDU BAR frames TXed */
+ uint32_t is_ampdu_bar_tx_retry; /* A-MPDU BAR frames TX rtry */
+ uint32_t is_ampdu_bar_tx_fail; /* A-MPDU BAR frames TX fail */
+
+ uint32_t is_spare[7];
};
/*
@@ -335,8 +340,10 @@
struct ieee80211req_mesh_route {
uint8_t imr_flags;
-#define IEEE80211_MESHRT_FLAGS_VALID 0x01
-#define IEEE80211_MESHRT_FLAGS_PROXY 0x02
+#define IEEE80211_MESHRT_FLAGS_DISCOVER 0x01
+#define IEEE80211_MESHRT_FLAGS_VALID 0x02
+#define IEEE80211_MESHRT_FLAGS_PROXY 0x04
+#define IEEE80211_MESHRT_FLAGS_GATE 0x08
uint8_t imr_dest[IEEE80211_ADDR_LEN];
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
uint16_t imr_nhops;
@@ -705,6 +712,7 @@
#define IEEE80211_IOC_MESH_PR_SIG 178 /* mesh sig protocol */
#define IEEE80211_IOC_MESH_PR_CC 179 /* mesh congestion protocol */
#define IEEE80211_IOC_MESH_PR_AUTH 180 /* mesh auth protocol */
+#define IEEE80211_IOC_MESH_GATE 181 /* mesh gate XXX: 173? */
#define IEEE80211_IOC_HWMP_ROOTMODE 190 /* HWMP root mode */
#define IEEE80211_IOC_HWMP_MAXHOPS 191 /* number of hops before drop */
@@ -715,6 +723,11 @@
#define IEEE80211_IOC_TDMA_SLOTLEN 203 /* TDMA: slot length (usecs) */
#define IEEE80211_IOC_TDMA_BINTERVAL 204 /* TDMA: beacon intvl (slots) */
+#define IEEE80211_IOC_QUIET 205 /* Quiet Enable/Disable */
+#define IEEE80211_IOC_QUIET_PERIOD 206 /* Quiet Period */
+#define IEEE80211_IOC_QUIET_OFFSET 207 /* Quiet Offset */
+#define IEEE80211_IOC_QUIET_DUR 208 /* Quiet Duration */
+#define IEEE80211_IOC_QUIET_COUNT 209 /* Quiet Count */
/*
* Parameters for controlling a scan requested with
* IEEE80211_IOC_SCAN_REQ.
Modified: trunk/sys/net80211/ieee80211_mesh.c
===================================================================
--- trunk/sys/net80211/ieee80211_mesh.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_mesh.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 The FreeBSD Foundation
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_mesh.c 322061 2017-08-04 20:24:23Z pfg $");
#endif
/*
@@ -52,6 +53,7 @@
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <net/bpf.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_llc.h>
@@ -59,6 +61,9 @@
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_action.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
#include <net80211/ieee80211_input.h>
#include <net80211/ieee80211_mesh.h>
@@ -68,6 +73,8 @@
static void mesh_vattach(struct ieee80211vap *);
static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void mesh_rt_cleanup_cb(void *);
+static void mesh_gatemode_setup(struct ieee80211vap *);
+static void mesh_gatemode_cb(void *);
static void mesh_linkchange(struct ieee80211_node *,
enum ieee80211_mesh_mlstate);
static void mesh_checkid(void *, struct ieee80211_node *);
@@ -74,9 +81,8 @@
static uint32_t mesh_generateid(struct ieee80211vap *);
static int mesh_checkpseq(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN], uint32_t);
-static struct ieee80211_node *
- mesh_find_txnode(struct ieee80211vap *,
- const uint8_t [IEEE80211_ADDR_LEN]);
+static void mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
+ struct ieee80211_mesh_route *);
static void mesh_forward(struct ieee80211vap *, struct mbuf *,
const struct ieee80211_meshcntl *);
static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int);
@@ -99,11 +105,16 @@
*/
static SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0,
"IEEE 802.11s parameters");
+static int ieee80211_mesh_gateint = -1;
+SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, gateint, CTLTYPE_INT | CTLFLAG_RW,
+ &ieee80211_mesh_gateint, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "mesh gate interval (ms)");
static int ieee80211_mesh_retrytimeout = -1;
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, retrytimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_retrytimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"Retry timeout (msec)");
static int ieee80211_mesh_holdingtimeout = -1;
+
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, holdingtimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_holdingtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"Holding state timeout (msec)");
@@ -111,10 +122,20 @@
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, confirmtimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_confirmtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"Confirm state timeout (msec)");
+static int ieee80211_mesh_backofftimeout = -1;
+SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, backofftimeout, CTLTYPE_INT | CTLFLAG_RW,
+ &ieee80211_mesh_backofftimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "Backoff timeout (msec). This is to throutles peering forever when "
+ "not receiving answer or is rejected by a neighbor");
static int ieee80211_mesh_maxretries = 2;
-SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLFLAG_RW,
&ieee80211_mesh_maxretries, 0,
"Maximum retries during peer link establishment");
+static int ieee80211_mesh_maxholding = 2;
+SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxholding, CTLFLAG_RW,
+ &ieee80211_mesh_maxholding, 0,
+ "Maximum times we are allowed to transition to HOLDING state before "
+ "backinoff during peer link establishment");
static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -122,14 +143,14 @@
static ieee80211_recv_action_func mesh_recv_action_meshpeering_open;
static ieee80211_recv_action_func mesh_recv_action_meshpeering_confirm;
static ieee80211_recv_action_func mesh_recv_action_meshpeering_close;
-static ieee80211_recv_action_func mesh_recv_action_meshlmetric_req;
-static ieee80211_recv_action_func mesh_recv_action_meshlmetric_rep;
+static ieee80211_recv_action_func mesh_recv_action_meshlmetric;
+static ieee80211_recv_action_func mesh_recv_action_meshgate;
static ieee80211_send_action_func mesh_send_action_meshpeering_open;
static ieee80211_send_action_func mesh_send_action_meshpeering_confirm;
static ieee80211_send_action_func mesh_send_action_meshpeering_close;
-static ieee80211_send_action_func mesh_send_action_meshlink_request;
-static ieee80211_send_action_func mesh_send_action_meshlink_reply;
+static ieee80211_send_action_func mesh_send_action_meshlmetric;
+static ieee80211_send_action_func mesh_send_action_meshgate;
static const struct ieee80211_mesh_proto_metric mesh_metric_airtime = {
.mpm_descr = "AIRTIME",
@@ -140,12 +161,24 @@
static struct ieee80211_mesh_proto_path mesh_proto_paths[4];
static struct ieee80211_mesh_proto_metric mesh_proto_metrics[4];
+#define RT_ENTRY_LOCK(rt) mtx_lock(&(rt)->rt_lock)
+#define RT_ENTRY_LOCK_ASSERT(rt) mtx_assert(&(rt)->rt_lock, MA_OWNED)
+#define RT_ENTRY_UNLOCK(rt) mtx_unlock(&(rt)->rt_lock)
+
#define MESH_RT_LOCK(ms) mtx_lock(&(ms)->ms_rt_lock)
#define MESH_RT_LOCK_ASSERT(ms) mtx_assert(&(ms)->ms_rt_lock, MA_OWNED)
#define MESH_RT_UNLOCK(ms) mtx_unlock(&(ms)->ms_rt_lock)
-MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
+MALLOC_DEFINE(M_80211_MESH_PREQ, "80211preq", "802.11 MESH Path Request frame");
+MALLOC_DEFINE(M_80211_MESH_PREP, "80211prep", "802.11 MESH Path Reply frame");
+MALLOC_DEFINE(M_80211_MESH_PERR, "80211perr", "802.11 MESH Path Error frame");
+/* The longer one of the lifetime should be stored as new lifetime */
+#define MESH_ROUTE_LIFETIME_MAX(a, b) (a > b ? a : b)
+
+MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh_rt", "802.11s routing table");
+MALLOC_DEFINE(M_80211_MESH_GT_RT, "80211mesh_gt", "802.11s known gates table");
+
/*
* Helper functions to manipulate the Mesh routing table.
*/
@@ -166,9 +199,10 @@
}
static struct ieee80211_mesh_route *
-mesh_rt_add_locked(struct ieee80211_mesh_state *ms,
+mesh_rt_add_locked(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN])
{
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt;
KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
@@ -179,9 +213,12 @@
rt = malloc(ALIGN(sizeof(struct ieee80211_mesh_route)) +
ms->ms_ppath->mpp_privlen, M_80211_MESH_RT, M_NOWAIT | M_ZERO);
if (rt != NULL) {
+ rt->rt_vap = vap;
IEEE80211_ADDR_COPY(rt->rt_dest, dest);
rt->rt_priv = (void *)ALIGN(&rt[1]);
- rt->rt_crtime = ticks;
+ mtx_init(&rt->rt_lock, "MBSS_RT", "802.11s route entry", MTX_DEF);
+ callout_init(&rt->rt_discovery, 1);
+ rt->rt_updtime = ticks; /* create time */
TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
}
return rt;
@@ -213,12 +250,56 @@
("%s: adding self to the routing table", __func__));
MESH_RT_LOCK(ms);
- rt = mesh_rt_add_locked(ms, dest);
+ rt = mesh_rt_add_locked(vap, dest);
MESH_RT_UNLOCK(ms);
return rt;
}
/*
+ * Update the route lifetime and returns the updated lifetime.
+ * If new_lifetime is zero and route is timedout it will be invalidated.
+ * new_lifetime is in msec
+ */
+int
+ieee80211_mesh_rt_update(struct ieee80211_mesh_route *rt, int new_lifetime)
+{
+ int timesince, now;
+ uint32_t lifetime = 0;
+
+ KASSERT(rt != NULL, ("route is NULL"));
+
+ now = ticks;
+ RT_ENTRY_LOCK(rt);
+
+ /* dont clobber a proxy entry gated by us */
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY && rt->rt_nhops == 0) {
+ RT_ENTRY_UNLOCK(rt);
+ return rt->rt_lifetime;
+ }
+
+ timesince = ticks_to_msecs(now - rt->rt_updtime);
+ rt->rt_updtime = now;
+ if (timesince >= rt->rt_lifetime) {
+ if (new_lifetime != 0) {
+ rt->rt_lifetime = new_lifetime;
+ }
+ else {
+ rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
+ rt->rt_lifetime = 0;
+ }
+ } else {
+ /* update what is left of lifetime */
+ rt->rt_lifetime = rt->rt_lifetime - timesince;
+ rt->rt_lifetime = MESH_ROUTE_LIFETIME_MAX(
+ new_lifetime, rt->rt_lifetime);
+ }
+ lifetime = rt->rt_lifetime;
+ RT_ENTRY_UNLOCK(rt);
+
+ return lifetime;
+}
+
+/*
* Add a proxy route (as needed) for the specified destination.
*/
void
@@ -231,7 +312,7 @@
MESH_RT_LOCK(ms);
rt = mesh_rt_find_locked(ms, dest);
if (rt == NULL) {
- rt = mesh_rt_add_locked(ms, dest);
+ rt = mesh_rt_add_locked(vap, dest);
if (rt == NULL) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
"%s", "unable to add proxy entry");
@@ -239,12 +320,14 @@
} else {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
"%s", "add proxy entry");
+ IEEE80211_ADDR_COPY(rt->rt_mesh_gate, vap->iv_myaddr);
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
| IEEE80211_MESHRT_FLAGS_PROXY;
}
- /* XXX assert PROXY? */
} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+ KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
+ ("no proxy flag for poxy entry"));
struct ieee80211com *ic = vap->iv_ic;
/*
* Fix existing entry created by received frames from
@@ -269,6 +352,13 @@
mesh_rt_del(struct ieee80211_mesh_state *ms, struct ieee80211_mesh_route *rt)
{
TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
+ /*
+ * Grab the lock before destroying it, to be sure no one else
+ * is holding the route.
+ */
+ RT_ENTRY_LOCK(rt);
+ callout_drain(&rt->rt_discovery);
+ mtx_destroy(&rt->rt_lock);
free(rt, M_80211_MESH_RT);
}
@@ -282,6 +372,13 @@
MESH_RT_LOCK(ms);
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) {
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ ms->ms_ppath->mpp_senderror(vap, dest, rt,
+ IEEE80211_REASON_MESH_PERR_NO_PROXY);
+ } else {
+ ms->ms_ppath->mpp_senderror(vap, dest, rt,
+ IEEE80211_REASON_MESH_PERR_DEST_UNREACH);
+ }
mesh_rt_del(ms, rt);
MESH_RT_UNLOCK(ms);
return;
@@ -333,8 +430,11 @@
return;
MESH_RT_LOCK(ms);
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 &&
- ticks - rt->rt_crtime >= ms->ms_ppath->mpp_inact)
+ /* Discover paths will be deleted by their own callout */
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_DISCOVER)
+ continue;
+ ieee80211_mesh_rt_update(rt, 0);
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
mesh_rt_del(ms, rt);
}
MESH_RT_UNLOCK(ms);
@@ -412,6 +512,48 @@
#undef N
static void
+mesh_gatemode_setup(struct ieee80211vap *vap)
+{
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+
+ /*
+ * NB: When a mesh gate is running as a ROOT it shall
+ * not send out periodic GANNs but instead mark the
+ * mesh gate flag for the corresponding proactive PREQ
+ * and RANN frames.
+ */
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_ROOT ||
+ (ms->ms_flags & IEEE80211_MESHFLAGS_GATE) == 0) {
+ callout_drain(&ms->ms_gatetimer);
+ return ;
+ }
+ callout_reset(&ms->ms_gatetimer, ieee80211_mesh_gateint,
+ mesh_gatemode_cb, vap);
+}
+
+static void
+mesh_gatemode_cb(void *arg)
+{
+ struct ieee80211vap *vap = (struct ieee80211vap *)arg;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_meshgann_ie gann;
+
+ gann.gann_flags = 0; /* Reserved */
+ gann.gann_hopcount = 0;
+ gann.gann_ttl = ms->ms_ttl;
+ IEEE80211_ADDR_COPY(gann.gann_addr, vap->iv_myaddr);
+ gann.gann_seq = ms->ms_gateseq++;
+ gann.gann_interval = ieee80211_mesh_gateint;
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, vap->iv_bss,
+ "send broadcast GANN (seq %u)", gann.gann_seq);
+
+ ieee80211_send_action(vap->iv_bss, IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_GANN, &gann);
+ mesh_gatemode_setup(vap);
+}
+
+static void
ieee80211_mesh_init(void)
{
@@ -421,42 +563,44 @@
/*
* Setup mesh parameters that depends on the clock frequency.
*/
+ ieee80211_mesh_gateint = msecs_to_ticks(10000);
ieee80211_mesh_retrytimeout = msecs_to_ticks(40);
ieee80211_mesh_holdingtimeout = msecs_to_ticks(40);
ieee80211_mesh_confirmtimeout = msecs_to_ticks(40);
+ ieee80211_mesh_backofftimeout = msecs_to_ticks(5000);
/*
* Register action frame handlers.
*/
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_OPEN,
mesh_recv_action_meshpeering_open);
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
mesh_recv_action_meshpeering_confirm);
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
mesh_recv_action_meshpeering_close);
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
- IEEE80211_ACTION_MESHLMETRIC_REQ, mesh_recv_action_meshlmetric_req);
- ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
- IEEE80211_ACTION_MESHLMETRIC_REP, mesh_recv_action_meshlmetric_rep);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_LMETRIC, mesh_recv_action_meshlmetric);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_GANN, mesh_recv_action_meshgate);
- ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_OPEN,
mesh_send_action_meshpeering_open);
- ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
mesh_send_action_meshpeering_confirm);
- ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHPEERING,
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
mesh_send_action_meshpeering_close);
- ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
- IEEE80211_ACTION_MESHLMETRIC_REQ,
- mesh_send_action_meshlink_request);
- ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESHLMETRIC,
- IEEE80211_ACTION_MESHLMETRIC_REP,
- mesh_send_action_meshlink_reply);
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_LMETRIC,
+ mesh_send_action_meshlmetric);
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_GANN,
+ mesh_send_action_meshgate);
/*
* Register Airtime Link Metric.
@@ -488,7 +632,7 @@
args[1] = ni->ni_mllid;
args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
}
@@ -532,9 +676,12 @@
ms->ms_seq = 0;
ms->ms_flags = (IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_FWD);
ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL;
+ TAILQ_INIT(&ms->ms_known_gates);
TAILQ_INIT(&ms->ms_routes);
mtx_init(&ms->ms_rt_lock, "MBSS", "802.11s routing table", MTX_DEF);
- callout_init(&ms->ms_cleantimer, CALLOUT_MPSAFE);
+ callout_init(&ms->ms_cleantimer, 1);
+ callout_init(&ms->ms_gatetimer, 1);
+ ms->ms_gateseq = 0;
mesh_select_proto_metric(vap, "AIRTIME");
KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
mesh_select_proto_path(vap, "HWMP");
@@ -563,8 +710,10 @@
if (ostate != IEEE80211_S_SCAN)
ieee80211_cancel_scan(vap); /* background scan */
ni = vap->iv_bss; /* NB: no reference held */
- if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
+ if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN) {
callout_drain(&ms->ms_cleantimer);
+ callout_drain(&ms->ms_gatetimer);
+ }
switch (nstate) {
case IEEE80211_S_INIT:
switch (ostate) {
@@ -689,6 +838,7 @@
ieee80211_node_authorize(vap->iv_bss);
callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
mesh_rt_cleanup_cb, vap);
+ mesh_gatemode_setup(vap);
break;
default:
break;
@@ -709,7 +859,44 @@
mesh_rt_cleanup_cb, vap);
}
+/*
+ * Mark a mesh STA as gate and return a pointer to it.
+ * If this is first time, we create a new gate route.
+ * Always update the path route to this mesh gate.
+ */
+struct ieee80211_mesh_gate_route *
+ieee80211_mesh_mark_gate(struct ieee80211vap *vap, const uint8_t *addr,
+ struct ieee80211_mesh_route *rt)
+{
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_gate_route *gr = NULL, *next;
+ int found = 0;
+ MESH_RT_LOCK(ms);
+ TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, next) {
+ if (IEEE80211_ADDR_EQ(gr->gr_addr, addr)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* New mesh gate add it to known table. */
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, addr,
+ "%s", "stored new gate information from pro-PREQ.");
+ gr = malloc(ALIGN(sizeof(struct ieee80211_mesh_gate_route)),
+ M_80211_MESH_GT_RT, M_NOWAIT | M_ZERO);
+ IEEE80211_ADDR_COPY(gr->gr_addr, addr);
+ TAILQ_INSERT_TAIL(&ms->ms_known_gates, gr, gr_next);
+ }
+ gr->gr_route = rt;
+ /* TODO: link from path route to gate route */
+ MESH_RT_UNLOCK(ms);
+
+ return gr;
+}
+
+
/*
* Helper function to note the Mesh Peer Link FSM change.
*/
@@ -820,8 +1007,8 @@
/*
* Iterate the routing table and locate the next hop.
*/
-static struct ieee80211_node *
-mesh_find_txnode(struct ieee80211vap *vap,
+struct ieee80211_node *
+ieee80211_mesh_find_txnode(struct ieee80211vap *vap,
const uint8_t dest[IEEE80211_ADDR_LEN])
{
struct ieee80211_mesh_route *rt;
@@ -829,17 +1016,130 @@
rt = ieee80211_mesh_rt_find(vap, dest);
if (rt == NULL)
return NULL;
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
- (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
- "%s: !valid or proxy, flags 0x%x", __func__, rt->rt_flags);
+ "%s: !valid, flags 0x%x", __func__, rt->rt_flags);
/* XXX stat */
return NULL;
}
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ rt = ieee80211_mesh_rt_find(vap, rt->rt_mesh_gate);
+ if (rt == NULL) return NULL;
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
+ "%s: meshgate !valid, flags 0x%x", __func__,
+ rt->rt_flags);
+ /* XXX stat */
+ return NULL;
+ }
+ }
return ieee80211_find_txnode(vap, rt->rt_nexthop);
}
+static void
+mesh_transmit_to_gate(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_mesh_route *rt_gate)
+{
+ struct ifnet *ifp = vap->iv_ifp;
+ struct ieee80211_node *ni;
+
+ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
+
+ ni = ieee80211_mesh_find_txnode(vap, rt_gate->rt_dest);
+ if (ni == NULL) {
+ ifp->if_oerrors++;
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * Send through the VAP packet transmit path.
+ * This consumes the node ref grabbed above and
+ * the mbuf, regardless of whether there's a problem
+ * or not.
+ */
+ (void) ieee80211_vap_pkt_send_dest(vap, m, ni);
+}
+
/*
+ * Forward the queued frames to known valid mesh gates.
+ * Assume destination to be outside the MBSS (i.e. proxy entry),
+ * If no valid mesh gates are known silently discard queued frames.
+ * After transmitting frames to all known valid mesh gates, this route
+ * will be marked invalid, and a new path discovery will happen in the hopes
+ * that (at least) one of the mesh gates have a new proxy entry for us to use.
+ */
+void
+ieee80211_mesh_forward_to_gates(struct ieee80211vap *vap,
+ struct ieee80211_mesh_route *rt_dest)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_route *rt_gate;
+ struct ieee80211_mesh_gate_route *gr = NULL, *gr_next;
+ struct mbuf *m, *mcopy, *next;
+
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+
+ KASSERT( rt_dest->rt_flags == IEEE80211_MESHRT_FLAGS_DISCOVER,
+ ("Route is not marked with IEEE80211_MESHRT_FLAGS_DISCOVER"));
+
+ /* XXX: send to more than one valid mash gate */
+ MESH_RT_LOCK(ms);
+
+ m = ieee80211_ageq_remove(&ic->ic_stageq,
+ (struct ieee80211_node *)(uintptr_t)
+ ieee80211_mac_hash(ic, rt_dest->rt_dest));
+
+ TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, gr_next) {
+ rt_gate = gr->gr_route;
+ if (rt_gate == NULL) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
+ rt_dest->rt_dest,
+ "mesh gate with no path %6D",
+ gr->gr_addr, ":");
+ continue;
+ }
+ if ((rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
+ continue;
+ KASSERT(rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_GATE,
+ ("route not marked as a mesh gate"));
+ KASSERT((rt_gate->rt_flags &
+ IEEE80211_MESHRT_FLAGS_PROXY) == 0,
+ ("found mesh gate that is also marked porxy"));
+ /*
+ * convert route to a proxy route gated by the current
+ * mesh gate, this is needed so encap can built data
+ * frame with correct address.
+ */
+ rt_dest->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
+ IEEE80211_MESHRT_FLAGS_VALID;
+ rt_dest->rt_ext_seq = 1; /* random value */
+ IEEE80211_ADDR_COPY(rt_dest->rt_mesh_gate, rt_gate->rt_dest);
+ IEEE80211_ADDR_COPY(rt_dest->rt_nexthop, rt_gate->rt_nexthop);
+ rt_dest->rt_metric = rt_gate->rt_metric;
+ rt_dest->rt_nhops = rt_gate->rt_nhops;
+ ieee80211_mesh_rt_update(rt_dest, ms->ms_ppath->mpp_inact);
+ MESH_RT_UNLOCK(ms);
+ /* XXX: lock?? */
+ mcopy = m_dup(m, M_NOWAIT);
+ for (; mcopy != NULL; mcopy = next) {
+ next = mcopy->m_nextpkt;
+ mcopy->m_nextpkt = NULL;
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
+ rt_dest->rt_dest,
+ "flush queued frame %p len %d", mcopy,
+ mcopy->m_pkthdr.len);
+ mesh_transmit_to_gate(vap, mcopy, rt_gate);
+ }
+ MESH_RT_LOCK(ms);
+ }
+ rt_dest->rt_flags = 0; /* Mark invalid */
+ m_freem(m);
+ MESH_RT_UNLOCK(ms);
+}
+
+/*
* Forward the specified frame.
* Decrement the TTL and set TA to our MAC address.
*/
@@ -850,7 +1150,6 @@
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ifnet *ifp = vap->iv_ifp;
- struct ifnet *parent = ic->ic_ifp;
const struct ieee80211_frame *wh =
mtod(m, const struct ieee80211_frame *);
struct mbuf *mcopy;
@@ -859,9 +1158,17 @@
struct ieee80211_node *ni;
int err;
- if (mc->mc_ttl == 0) {
+ /* This is called from the RX path - don't hold this lock */
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+
+ /*
+ * mesh ttl of 1 means we are the last one receving it,
+ * according to amendment we decrement and then check if
+ * 0, if so we dont forward.
+ */
+ if (mc->mc_ttl < 1) {
IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
- "%s", "frame not fwd'd, ttl 0");
+ "%s", "frame not fwd'd, ttl 1");
vap->iv_stats.is_mesh_fwd_ttl++;
return;
}
@@ -871,7 +1178,7 @@
vap->iv_stats.is_mesh_fwd_disabled++;
return;
}
- mcopy = m_dup(m, M_DONTWAIT);
+ mcopy = m_dup(m, M_NOWAIT);
if (mcopy == NULL) {
IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
"%s", "frame not fwd'd, cannot dup");
@@ -899,10 +1206,18 @@
ni = ieee80211_ref_node(vap->iv_bss);
mcopy->m_flags |= M_MCAST;
} else {
- ni = mesh_find_txnode(vap, whcopy->i_addr3);
+ ni = ieee80211_mesh_find_txnode(vap, whcopy->i_addr3);
if (ni == NULL) {
+ /*
+ * [Optional] any of the following three actions:
+ * o silently discard
+ * o trigger a path discovery
+ * o inform TA that meshDA is unknown.
+ */
IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
"%s", "frame not fwd'd, no path");
+ ms->ms_ppath->mpp_senderror(vap, whcopy->i_addr3, NULL,
+ IEEE80211_REASON_MESH_PERR_NO_FI);
vap->iv_stats.is_mesh_fwd_nopath++;
m_freem(mcopy);
return;
@@ -917,7 +1232,20 @@
/* XXX do we know m_nextpkt is NULL? */
mcopy->m_pkthdr.rcvif = (void *) ni;
- err = parent->if_transmit(parent, mcopy);
+
+ /*
+ * XXX this bypasses all of the VAP TX handling; it passes frames
+ * directly to the parent interface.
+ *
+ * Because of this, there's no TX lock being held as there's no
+ * encaps state being used.
+ *
+ * Doing a direct parent transmit may not be the correct thing
+ * to do here; we'll have to re-think this soon.
+ */
+ IEEE80211_TX_LOCK(ic);
+ err = ieee80211_parent_xmitpkt(ic, mcopy);
+ IEEE80211_TX_UNLOCK(ic);
if (err != 0) {
/* NB: IFQ_HANDOFF reclaims mbuf */
ieee80211_free_node(ni);
@@ -929,9 +1257,10 @@
static struct mbuf *
mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
{
-#define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
+#define WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
+#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
- sizeof(struct ieee80211_meshcntl_ae11)];
+ sizeof(struct ieee80211_meshcntl_ae10)];
const struct ieee80211_qosframe_addr4 *wh;
const struct ieee80211_meshcntl_ae10 *mc;
struct ether_header *eh;
@@ -965,13 +1294,14 @@
m_adj(m, hdrlen - sizeof(*eh));
}
eh = mtod(m, struct ether_header *);
- ae = mc->mc_flags & 3;
+ ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
- if (ae == 0) {
+ if (ae == IEEE80211_MESH_AE_00) {
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
- } else if (ae == 1) {
- IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
+ } else if (ae == IEEE80211_MESH_AE_01) {
+ IEEE80211_ADDR_COPY(eh->ether_shost,
+ MC01(mc)->mc_addr4);
} else {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
(const struct ieee80211_frame *)wh, NULL,
@@ -981,12 +1311,12 @@
return NULL;
}
} else {
- if (ae == 0) {
+ if (ae == IEEE80211_MESH_AE_00) {
IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
- } else if (ae == 2) {
- IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
- IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
+ } else if (ae == IEEE80211_MESH_AE_10) {
+ IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr5);
+ IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr6);
} else {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
(const struct ieee80211_frame *)wh, NULL,
@@ -996,19 +1326,20 @@
return NULL;
}
}
-#ifdef ALIGNED_POINTER
+#ifndef __NO_STRICT_ALIGNMENT
if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
m = ieee80211_realign(vap, m, sizeof(*eh));
if (m == NULL)
return NULL;
}
-#endif /* ALIGNED_POINTER */
+#endif /* !__NO_STRICT_ALIGNMENT */
if (llc != NULL) {
eh = mtod(m, struct ether_header *);
eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
}
return m;
-#undef WDIR
+#undef WDIR
+#undef MC01
}
/*
@@ -1024,12 +1355,13 @@
KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
- KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
- if (ae == 2) { /* ucast w/ proxy */
+ KASSERT(ae == IEEE80211_MESH_AE_00 || ae == IEEE80211_MESH_AE_10,
+ ("bad AE %d", ae));
+ if (ae == IEEE80211_MESH_AE_10) { /* ucast w/ proxy */
const struct ieee80211_meshcntl_ae10 *mc10 =
(const struct ieee80211_meshcntl_ae10 *) mc;
struct ieee80211_mesh_route *rt =
- ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
+ ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
/* check for proxy route to ourself */
return (rt != NULL &&
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
@@ -1037,19 +1369,184 @@
return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
}
+/*
+ * Verifies transmitter, updates lifetime, precursor list and forwards data.
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
static int
+mesh_recv_indiv_data_to_fwrd(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+ struct ieee80211_qosframe_addr4 *qwh;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_route *rt_meshda, *rt_meshsa;
+
+ /* This is called from the RX path - don't hold this lock */
+ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
+
+ qwh = (struct ieee80211_qosframe_addr4 *)wh;
+
+ /*
+ * TODO:
+ * o verify addr2 is a legitimate transmitter
+ * o lifetime of precursor of addr3 (addr2) is max(init, curr)
+ * o lifetime of precursor of addr4 (nexthop) is max(init, curr)
+ */
+
+ /* set lifetime of addr3 (meshDA) to initial value */
+ rt_meshda = ieee80211_mesh_rt_find(vap, qwh->i_addr3);
+ if (rt_meshda == NULL) {
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, qwh->i_addr2,
+ "no route to meshDA(%6D)", qwh->i_addr3, ":");
+ /*
+ * [Optional] any of the following three actions:
+ * o silently discard [X]
+ * o trigger a path discovery [ ]
+ * o inform TA that meshDA is unknown. [ ]
+ */
+ /* XXX: stats */
+ return (-1);
+ }
+
+ ieee80211_mesh_rt_update(rt_meshda, ticks_to_msecs(
+ ms->ms_ppath->mpp_inact));
+
+ /* set lifetime of addr4 (meshSA) to initial value */
+ rt_meshsa = ieee80211_mesh_rt_find(vap, qwh->i_addr4);
+ KASSERT(rt_meshsa != NULL, ("no route"));
+ ieee80211_mesh_rt_update(rt_meshsa, ticks_to_msecs(
+ ms->ms_ppath->mpp_inact));
+
+ mesh_forward(vap, m, mc);
+ return (1); /* dont process locally */
+}
+
+/*
+ * Verifies transmitter, updates lifetime, precursor list and process data
+ * locally, if data is proxy with AE = 10 it could mean data should go
+ * on another mesh path or data should be forwarded to the DS.
+ *
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
+static int
+mesh_recv_indiv_data_to_me(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+ struct ieee80211_qosframe_addr4 *qwh;
+ const struct ieee80211_meshcntl_ae10 *mc10;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_route *rt;
+ int ae;
+
+ /* This is called from the RX path - don't hold this lock */
+ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
+
+ qwh = (struct ieee80211_qosframe_addr4 *)wh;
+ mc10 = (const struct ieee80211_meshcntl_ae10 *)mc;
+
+ /*
+ * TODO:
+ * o verify addr2 is a legitimate transmitter
+ * o lifetime of precursor entry is max(init, curr)
+ */
+
+ /* set lifetime of addr4 (meshSA) to initial value */
+ rt = ieee80211_mesh_rt_find(vap, qwh->i_addr4);
+ KASSERT(rt != NULL, ("no route"));
+ ieee80211_mesh_rt_update(rt, ticks_to_msecs(ms->ms_ppath->mpp_inact));
+ rt = NULL;
+
+ ae = mc10->mc_flags & IEEE80211_MESH_AE_MASK;
+ KASSERT(ae == IEEE80211_MESH_AE_00 ||
+ ae == IEEE80211_MESH_AE_10, ("bad AE %d", ae));
+ if (ae == IEEE80211_MESH_AE_10) {
+ if (IEEE80211_ADDR_EQ(mc10->mc_addr5, qwh->i_addr3)) {
+ return (0); /* process locally */
+ }
+
+ rt = ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
+ if (rt != NULL &&
+ (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
+ (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) == 0) {
+ /*
+ * Forward on another mesh-path, according to
+ * amendment as specified in 9.32.4.1
+ */
+ IEEE80211_ADDR_COPY(qwh->i_addr3, mc10->mc_addr5);
+ mesh_forward(vap, m,
+ (const struct ieee80211_meshcntl *)mc10);
+ return (1); /* dont process locally */
+ }
+ /*
+ * All other cases: forward of MSDUs from the MBSS to DS indiv.
+ * addressed according to 13.11.3.2.
+ */
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, qwh->i_addr2,
+ "forward frame to DS, SA(%6D) DA(%6D)",
+ mc10->mc_addr6, ":", mc10->mc_addr5, ":");
+ }
+ return (0); /* process locally */
+}
+
+/*
+ * Try to forward the group addressed data on to other mesh STAs, and
+ * also to the DS.
+ *
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
+static int
+mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+
+ /* This is called from the RX path - don't hold this lock */
+ IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
+
+ mesh_forward(vap, m, mc);
+
+ if(mc->mc_ttl > 0) {
+ if (mc->mc_flags & IEEE80211_MESH_AE_01) {
+ /*
+ * Forward of MSDUs from the MBSS to DS group addressed
+ * (according to 13.11.3.2)
+ * This happens by delivering the packet, and a bridge
+ * will sent it on another port member.
+ */
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE &&
+ ms->ms_flags & IEEE80211_MESHFLAGS_FWD)
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH,
+ MC01(mc)->mc_addr4, "%s",
+ "forward from MBSS to the DS");
+ }
+ }
+ return (0); /* process locally */
+#undef MC01
+}
+
+static int
mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
#define HAS_SEQ(type) ((type & 0x4) == 0)
+#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
+#define MC10(mc) ((const struct ieee80211_meshcntl_ae10 *)mc)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = vap->iv_ifp;
struct ieee80211_frame *wh;
const struct ieee80211_meshcntl *mc;
- int hdrspace, meshdrlen, need_tap;
- uint8_t dir, type, subtype, qos;
+ int hdrspace, meshdrlen, need_tap, error;
+ uint8_t dir, type, subtype, ae;
uint32_t seq;
- uint8_t *addr;
+ const uint8_t *addr;
+ uint8_t qos[2];
ieee80211_seq rxseq;
KASSERT(ni != NULL, ("null node"));
@@ -1058,6 +1555,9 @@
need_tap = 1; /* mbuf need to be tapped. */
type = -1; /* undefined */
+ /* This is called from the RX path - don't hold this lock */
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+
if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
ni->ni_macaddr, NULL,
@@ -1120,7 +1620,7 @@
*
* NB: this check is also done upon peering link initiation.
*/
- if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh->i_addr2)) {
+ if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
wh, NULL, "%s", "disallowed by ACL");
vap->iv_stats.is_rx_acl++;
@@ -1138,7 +1638,7 @@
ni->ni_mlstate);
vap->iv_stats.is_mesh_nolink++;
goto out;
- }
+ }
if (dir != IEEE80211_FC1_DIR_FROMDS &&
dir != IEEE80211_FC1_DIR_DSTODS) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
@@ -1146,8 +1646,64 @@
vap->iv_stats.is_rx_wrongdir++;
goto err;
}
+
+ /* All Mesh data frames are QoS subtype */
+ if (!HAS_SEQ(type)) {
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
+ wh, "data", "incorrect subtype 0x%x", subtype);
+ vap->iv_stats.is_rx_badsubtype++;
+ goto err;
+ }
+
+ /*
+ * Next up, any fragmentation.
+ * XXX: we defrag before we even try to forward,
+ * Mesh Control field is not present in sub-sequent
+ * fragmented frames. This is in contrast to Draft 4.0.
+ */
+ hdrspace = ieee80211_hdrspace(ic, wh);
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ m = ieee80211_defrag(ni, m, hdrspace);
+ if (m == NULL) {
+ /* Fragment dropped or frame not complete yet */
+ goto out;
+ }
+ }
+ wh = mtod(m, struct ieee80211_frame *); /* NB: after defrag */
+
+ /*
+ * Now we have a complete Mesh Data frame.
+ */
+
+ /*
+ * Only fromDStoDS data frames use 4 address qos frames
+ * as specified in amendment. Otherwise addr4 is located
+ * in the Mesh Control field and a 3 address qos frame
+ * is used.
+ */
+ if (IEEE80211_IS_DSTODS(wh))
+ *(uint16_t *)qos = *(uint16_t *)
+ ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
+ else
+ *(uint16_t *)qos = *(uint16_t *)
+ ((struct ieee80211_qosframe *)wh)->i_qos;
+
+ /*
+ * NB: The mesh STA sets the Mesh Control Present
+ * subfield to 1 in the Mesh Data frame containing
+ * an unfragmented MSDU, an A-MSDU, or the first
+ * fragment of an MSDU.
+ * After defrag it should always be present.
+ */
+ if (!(qos[1] & IEEE80211_QOS_MC)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
+ ni->ni_macaddr, NULL,
+ "%s", "Mesh control field not present");
+ vap->iv_stats.is_rx_elem_missing++; /* XXX: kinda */
+ goto err;
+ }
+
/* pull up enough to get to the mesh control */
- hdrspace = ieee80211_hdrspace(ic, wh);
if (m->m_len < hdrspace + sizeof(struct ieee80211_meshcntl) &&
(m = m_pullup(m, hdrspace +
sizeof(struct ieee80211_meshcntl))) == NULL) {
@@ -1164,12 +1720,28 @@
*/
mc = (const struct ieee80211_meshcntl *)
(mtod(m, const uint8_t *) + hdrspace);
+ ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
meshdrlen = sizeof(struct ieee80211_meshcntl) +
- (mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
+ ae * IEEE80211_ADDR_LEN;
hdrspace += meshdrlen;
+
+ /* pull complete hdrspace = ieee80211_hdrspace + meshcontrol */
+ if ((meshdrlen > sizeof(struct ieee80211_meshcntl)) &&
+ (m->m_len < hdrspace) &&
+ ((m = m_pullup(m, hdrspace)) == NULL)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, NULL,
+ "data too short: expecting %u", hdrspace);
+ vap->iv_stats.is_rx_tooshort++;
+ goto out; /* XXX */
+ }
+ /* XXX: are we sure there is no reallocating after m_pullup? */
+
seq = LE_READ_4(mc->mc_seq);
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
addr = wh->i_addr3;
+ else if (ae == IEEE80211_MESH_AE_01)
+ addr = MC01(mc)->mc_addr4;
else
addr = ((struct ieee80211_qosframe_addr4 *)wh)->i_addr4;
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, addr)) {
@@ -1183,38 +1755,22 @@
goto out;
}
- /*
- * Potentially forward packet. See table s36 (p140)
- * for the rules. XXX tap fwd'd packets not for us?
- */
- if (dir == IEEE80211_FC1_DIR_FROMDS ||
- !mesh_isucastforme(vap, wh, mc)) {
- mesh_forward(vap, m, mc);
- if (dir == IEEE80211_FC1_DIR_DSTODS)
- goto out;
- /* NB: fall thru to deliver mcast frames locally */
- }
-
- /*
- * Save QoS bits for use below--before we strip the header.
- */
- if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
- qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
- ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
- ((struct ieee80211_qosframe *)wh)->i_qos[0];
+ /* This code "routes" the frame to the right control path */
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr3))
+ error =
+ mesh_recv_indiv_data_to_me(vap, m, wh, mc);
+ else if (IEEE80211_IS_MULTICAST(wh->i_addr3))
+ error = mesh_recv_group_data(vap, m, wh, mc);
+ else
+ error = mesh_recv_indiv_data_to_fwrd(vap, m,
+ wh, mc);
} else
- qos = 0;
- /*
- * Next up, any fragmentation.
- */
- if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
- m = ieee80211_defrag(ni, m, hdrspace);
- if (m == NULL) {
- /* Fragment dropped or frame not complete yet */
- goto out;
- }
- }
- wh = NULL; /* no longer valid, catch any uses */
+ error = mesh_recv_group_data(vap, m, wh, mc);
+ if (error < 0)
+ goto err;
+ else if (error > 0)
+ goto out;
if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_rx(vap, m);
@@ -1236,7 +1792,7 @@
IEEE80211_NODE_STAT(ni, rx_decap);
goto err;
}
- if (qos & IEEE80211_QOS_AMSDU) {
+ if (qos[0] & IEEE80211_QOS_AMSDU) {
m = ieee80211_decap_amsdu(ni, m);
if (m == NULL)
return IEEE80211_FC0_TYPE_DATA;
@@ -1269,7 +1825,7 @@
ether_sprintf(wh->i_addr2), rssi);
}
#endif
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, NULL, "%s", "WEP set but not permitted");
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
@@ -1296,6 +1852,9 @@
m_freem(m);
}
return type;
+#undef HAS_SEQ
+#undef MC01
+#undef MC10
}
static void
@@ -1306,6 +1865,7 @@
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
+ struct ieee80211_mesh_route *rt;
uint8_t *frm, *efrm;
wh = mtod(m0, struct ieee80211_frame *);
@@ -1378,8 +1938,7 @@
/*
* Peer only based on the current ACL policy.
*/
- if (vap->iv_acl != NULL &&
- !vap->iv_acl->iac_check(vap, wh->i_addr2)) {
+ if (vap->iv_acl != NULL && !vap->iv_acl->iac_check(vap, wh)) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ACL,
wh, NULL, "%s", "disallowed by ACL");
vap->iv_stats.is_rx_acl++;
@@ -1396,23 +1955,47 @@
}
/*
* Automatically peer with discovered nodes if possible.
- * XXX backoff on repeated failure
*/
if (ni != vap->iv_bss &&
- (ms->ms_flags & IEEE80211_MESHFLAGS_AP) &&
- ni->ni_mlstate == IEEE80211_NODE_MESH_IDLE) {
- uint16_t args[1];
+ (ms->ms_flags & IEEE80211_MESHFLAGS_AP)) {
+ switch (ni->ni_mlstate) {
+ case IEEE80211_NODE_MESH_IDLE:
+ {
+ uint16_t args[1];
- ni->ni_mlpid = mesh_generateid(vap);
- if (ni->ni_mlpid == 0)
- return;
- mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENSNT);
- args[0] = ni->ni_mlpid;
- ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
- IEEE80211_ACTION_MESHPEERING_OPEN, args);
- ni->ni_mlrcnt = 0;
- mesh_peer_timeout_setup(ni);
+ /* Wait for backoff callout to reset counter */
+ if (ni->ni_mlhcnt >= ieee80211_mesh_maxholding)
+ return;
+
+ ni->ni_mlpid = mesh_generateid(vap);
+ if (ni->ni_mlpid == 0)
+ return;
+ mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENSNT);
+ args[0] = ni->ni_mlpid;
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_SELF_PROT,
+ IEEE80211_ACTION_MESHPEERING_OPEN, args);
+ ni->ni_mlrcnt = 0;
+ mesh_peer_timeout_setup(ni);
+ break;
+ }
+ case IEEE80211_NODE_MESH_ESTABLISHED:
+ {
+ /*
+ * Valid beacon from a peer mesh STA
+ * bump TA lifetime
+ */
+ rt = ieee80211_mesh_rt_find(vap, wh->i_addr2);
+ if(rt != NULL) {
+ ieee80211_mesh_rt_update(rt,
+ ticks_to_msecs(
+ ms->ms_ppath->mpp_inact));
+ }
+ break;
+ }
+ default:
+ break; /* ignore */
+ }
}
break;
}
@@ -1542,8 +2125,7 @@
}
/*
- * Parse meshpeering action ie's for open+confirm frames; the
- * important bits are returned in the supplied structure.
+ * Parse meshpeering action ie's for MPM frames
*/
static const struct ieee80211_meshpeer_ie *
mesh_parse_meshpeering_action(struct ieee80211_node *ni,
@@ -1553,7 +2135,9 @@
{
struct ieee80211vap *vap = ni->ni_vap;
const struct ieee80211_meshpeer_ie *mpie;
+ uint16_t args[3];
const uint8_t *meshid, *meshconf, *meshpeer;
+ uint8_t sendclose = 0; /* 1 = MPM frame rejected, close will be sent */
meshid = meshconf = meshpeer = NULL;
while (efrm - frm > 1) {
@@ -1569,15 +2153,28 @@
meshpeer = frm;
mpie = (const struct ieee80211_meshpeer_ie *) frm;
memset(mp, 0, sizeof(*mp));
+ mp->peer_len = mpie->peer_len;
+ mp->peer_proto = LE_READ_2(&mpie->peer_proto);
mp->peer_llinkid = LE_READ_2(&mpie->peer_llinkid);
- /* NB: peer link ID is optional on these frames */
- if (subtype == IEEE80211_MESH_PEER_LINK_CLOSE &&
- mpie->peer_len == 8) {
- mp->peer_linkid = 0;
- mp->peer_rcode = LE_READ_2(&mpie->peer_linkid);
- } else {
- mp->peer_linkid = LE_READ_2(&mpie->peer_linkid);
- mp->peer_rcode = LE_READ_2(&mpie->peer_rcode);
+ switch (subtype) {
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ mp->peer_linkid =
+ LE_READ_2(&mpie->peer_linkid);
+ break;
+ case IEEE80211_ACTION_MESHPEERING_CLOSE:
+ /* NB: peer link ID is optional */
+ if (mpie->peer_len ==
+ (IEEE80211_MPM_BASE_SZ + 2)) {
+ mp->peer_linkid = 0;
+ mp->peer_rcode =
+ LE_READ_2(&mpie->peer_linkid);
+ } else {
+ mp->peer_linkid =
+ LE_READ_2(&mpie->peer_linkid);
+ mp->peer_rcode =
+ LE_READ_2(&mpie->peer_rcode);
+ }
+ break;
}
break;
}
@@ -1585,22 +2182,46 @@
}
/*
- * Verify the contents of the frame. Action frames with
- * close subtype don't have a Mesh Configuration IE.
- * If if fails validation, close the peer link.
+ * Verify the contents of the frame.
+ * If it fails validation, close the peer link.
*/
- KASSERT(meshpeer != NULL &&
- subtype != IEEE80211_ACTION_MESHPEERING_CLOSE,
- ("parsing close action"));
+ if (mesh_verify_meshpeer(vap, subtype, (const uint8_t *)mp)) {
+ sendclose = 1;
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ wh, NULL, "%s", "MPM validation failed");
+ }
- if (mesh_verify_meshid(vap, meshid) ||
- mesh_verify_meshpeer(vap, subtype, meshpeer) ||
+ /* If meshid is not the same reject any frames type. */
+ if (sendclose == 0 && mesh_verify_meshid(vap, meshid)) {
+ sendclose = 1;
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ wh, NULL, "%s", "not for our mesh");
+ if (subtype == IEEE80211_ACTION_MESHPEERING_CLOSE) {
+ /*
+ * Standard not clear about this, if we dont ignore
+ * there will be an endless loop between nodes sending
+ * CLOSE frames between each other with wrong meshid.
+ * Discard and timers will bring FSM to IDLE state.
+ */
+ return NULL;
+ }
+ }
+
+ /*
+ * Close frames are accepted if meshid is the same.
+ * Verify the other two types.
+ */
+ if (sendclose == 0 && subtype != IEEE80211_ACTION_MESHPEERING_CLOSE &&
mesh_verify_meshconf(vap, meshconf)) {
- uint16_t args[3];
-
+ sendclose = 1;
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
- wh, NULL, "%s", "not for our mesh");
+ wh, NULL, "%s", "configuration missmatch");
+ }
+
+ if (sendclose) {
vap->iv_stats.is_rx_mgtdiscard++;
switch (ni->ni_mlstate) {
case IEEE80211_NODE_MESH_IDLE:
@@ -1613,9 +2234,17 @@
case IEEE80211_NODE_MESH_CONFIRMRCV:
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
- args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
+ /* Reason codes for rejection */
+ switch (subtype) {
+ case IEEE80211_ACTION_MESHPEERING_OPEN:
+ args[2] = IEEE80211_REASON_MESH_CPVIOLATION;
+ break;
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ args[2] = IEEE80211_REASON_MESH_INCONS_PARAMS;
+ break;
+ }
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -1624,6 +2253,7 @@
}
return NULL;
}
+
return (const struct ieee80211_meshpeer_ie *) mp;
}
@@ -1633,6 +2263,7 @@
const uint8_t *frm, const uint8_t *efrm)
{
struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_meshpeer_ie ie;
const struct ieee80211_meshpeer_ie *meshpeer;
uint16_t args[3];
@@ -1650,6 +2281,19 @@
switch (ni->ni_mlstate) {
case IEEE80211_NODE_MESH_IDLE:
+ /* Reject open request if reached our maximum neighbor count */
+ if (ms->ms_neighbors >= IEEE80211_MESH_MAX_NEIGHBORS) {
+ args[0] = meshpeer->peer_llinkid;
+ args[1] = 0;
+ args[2] = IEEE80211_REASON_MESH_MAX_PEERS;
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_SELF_PROT,
+ IEEE80211_ACTION_MESHPEERING_CLOSE,
+ args);
+ /* stay in IDLE state */
+ return (0);
+ }
+ /* Open frame accepted */
mesh_linkchange(ni, IEEE80211_NODE_MESH_OPENRCV);
ni->ni_mllid = meshpeer->peer_llinkid;
ni->ni_mlpid = mesh_generateid(vap);
@@ -1658,13 +2302,13 @@
args[0] = ni->ni_mlpid;
/* Announce we're open too... */
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_OPEN, args);
/* ...and confirm the link. */
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args);
mesh_peer_timeout_setup(ni);
@@ -1676,7 +2320,7 @@
args[1] = ni->ni_mlpid;
args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -1687,7 +2331,7 @@
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args);
break;
@@ -1697,7 +2341,7 @@
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args);
/* NB: don't setup/clear any timeout */
@@ -1709,7 +2353,7 @@
args[1] = ni->ni_mllid;
args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni,
@@ -1722,7 +2366,7 @@
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args);
mesh_peer_timeout_stop(ni);
@@ -1733,7 +2377,7 @@
args[1] = ni->ni_mlpid;
args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -1743,7 +2387,7 @@
args[0] = ni->ni_mlpid;
args[1] = ni->ni_mllid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CONFIRM,
args);
break;
@@ -1750,9 +2394,10 @@
case IEEE80211_NODE_MESH_HOLDING:
args[0] = ni->ni_mlpid;
args[1] = meshpeer->peer_llinkid;
- args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
+ /* Standard not clear about what the reaason code should be */
+ args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
break;
@@ -1788,13 +2433,15 @@
break;
case IEEE80211_NODE_MESH_OPENSNT:
mesh_linkchange(ni, IEEE80211_NODE_MESH_CONFIRMRCV);
+ mesh_peer_timeout_setup(ni);
break;
case IEEE80211_NODE_MESH_HOLDING:
args[0] = ni->ni_mlpid;
args[1] = meshpeer->peer_llinkid;
- args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
+ /* Standard not clear about what the reaason code should be */
+ args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
break;
@@ -1804,7 +2451,7 @@
args[1] = ni->ni_mllid;
args[2] = IEEE80211_REASON_PEER_LINK_CANCELED;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -1827,8 +2474,23 @@
const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
+ struct ieee80211_meshpeer_ie ie;
+ const struct ieee80211_meshpeer_ie *meshpeer;
uint16_t args[3];
+ /* +2 for action + code */
+ meshpeer = mesh_parse_meshpeering_action(ni, wh, frm+2, efrm, &ie,
+ IEEE80211_ACTION_MESHPEERING_CLOSE);
+ if (meshpeer == NULL) {
+ return 0;
+ }
+
+ /*
+ * XXX: check reason code, for example we could receive
+ * IEEE80211_REASON_MESH_MAX_PEERS then we should not attempt
+ * to peer again.
+ */
+
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
ni, "%s", "recv PEER CLOSE");
@@ -1844,7 +2506,7 @@
args[1] = ni->ni_mllid;
args[2] = IEEE80211_REASON_MESH_CLOSE_RCVD;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE,
args);
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -1852,7 +2514,7 @@
break;
case IEEE80211_NODE_MESH_HOLDING:
mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE);
- mesh_peer_timeout_setup(ni);
+ mesh_peer_timeout_stop(ni);
break;
}
return 0;
@@ -1862,41 +2524,202 @@
* Link Metric handling.
*/
static int
-mesh_recv_action_meshlmetric_req(struct ieee80211_node *ni,
+mesh_recv_action_meshlmetric(struct ieee80211_node *ni,
const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
- uint32_t metric;
+ const struct ieee80211_meshlmetric_ie *ie =
+ (const struct ieee80211_meshlmetric_ie *)
+ (frm+2); /* action + code */
+ struct ieee80211_meshlmetric_ie lm_rep;
+
+ if (ie->lm_flags & IEEE80211_MESH_LMETRIC_FLAGS_REQ) {
+ lm_rep.lm_flags = 0;
+ lm_rep.lm_metric = mesh_airtime_calc(ni);
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_LMETRIC,
+ &lm_rep);
+ }
+ /* XXX: else do nothing for now */
+ return 0;
+}
- metric = mesh_airtime_calc(ni);
- ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHLMETRIC,
- IEEE80211_ACTION_MESHLMETRIC_REP,
- &metric);
+/*
+ * Parse meshgate action ie's for GANN frames.
+ * Returns -1 if parsing fails, otherwise 0.
+ */
+static int
+mesh_parse_meshgate_action(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh, /* XXX for VERIFY_LENGTH */
+ struct ieee80211_meshgann_ie *ie, const uint8_t *frm, const uint8_t *efrm)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ const struct ieee80211_meshgann_ie *gannie;
+
+ while (efrm - frm > 1) {
+ IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return -1);
+ switch (*frm) {
+ case IEEE80211_ELEMID_MESHGANN:
+ gannie = (const struct ieee80211_meshgann_ie *) frm;
+ memset(ie, 0, sizeof(*ie));
+ ie->gann_ie = gannie->gann_ie;
+ ie->gann_len = gannie->gann_len;
+ ie->gann_flags = gannie->gann_flags;
+ ie->gann_hopcount = gannie->gann_hopcount;
+ ie->gann_ttl = gannie->gann_ttl;
+ IEEE80211_ADDR_COPY(ie->gann_addr, gannie->gann_addr);
+ ie->gann_seq = LE_READ_4(&gannie->gann_seq);
+ ie->gann_interval = LE_READ_2(&gannie->gann_interval);
+ break;
+ }
+ frm += frm[1] + 2;
+ }
+
return 0;
}
+/*
+ * Mesh Gate Announcement handling.
+ */
static int
-mesh_recv_action_meshlmetric_rep(struct ieee80211_node *ni,
+mesh_recv_action_meshgate(struct ieee80211_node *ni,
const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_mesh_gate_route *gr, *next;
+ struct ieee80211_mesh_route *rt_gate;
+ struct ieee80211_meshgann_ie pgann;
+ struct ieee80211_meshgann_ie ie;
+ int found = 0;
+
+ /* +2 for action + code */
+ if (mesh_parse_meshgate_action(ni, wh, &ie, frm+2, efrm) != 0) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
+ ni->ni_macaddr, NULL, "%s",
+ "GANN parsing failed");
+ vap->iv_stats.is_rx_mgtdiscard++;
+ return (0);
+ }
+
+ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, ie.gann_addr))
+ return 0;
+
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, ni->ni_macaddr,
+ "received GANN, meshgate: %6D (seq %u)", ie.gann_addr, ":",
+ ie.gann_seq);
+
+ if (ms == NULL)
+ return (0);
+ MESH_RT_LOCK(ms);
+ TAILQ_FOREACH_SAFE(gr, &ms->ms_known_gates, gr_next, next) {
+ if (!IEEE80211_ADDR_EQ(gr->gr_addr, ie.gann_addr))
+ continue;
+ if (ie.gann_seq <= gr->gr_lastseq) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
+ ni->ni_macaddr, NULL,
+ "GANN old seqno %u <= %u",
+ ie.gann_seq, gr->gr_lastseq);
+ MESH_RT_UNLOCK(ms);
+ return (0);
+ }
+ /* corresponding mesh gate found & GANN accepted */
+ found = 1;
+ break;
+
+ }
+ if (found == 0) {
+ /* this GANN is from a new mesh Gate add it to known table. */
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, ie.gann_addr,
+ "stored new GANN information, seq %u.", ie.gann_seq);
+ gr = malloc(ALIGN(sizeof(struct ieee80211_mesh_gate_route)),
+ M_80211_MESH_GT_RT, M_NOWAIT | M_ZERO);
+ IEEE80211_ADDR_COPY(gr->gr_addr, ie.gann_addr);
+ TAILQ_INSERT_TAIL(&ms->ms_known_gates, gr, gr_next);
+ }
+ gr->gr_lastseq = ie.gann_seq;
+
+ /* check if we have a path to this gate */
+ rt_gate = mesh_rt_find_locked(ms, gr->gr_addr);
+ if (rt_gate != NULL &&
+ rt_gate->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) {
+ gr->gr_route = rt_gate;
+ rt_gate->rt_flags |= IEEE80211_MESHRT_FLAGS_GATE;
+ }
+
+ MESH_RT_UNLOCK(ms);
+
+ /* popagate only if decremented ttl >= 1 && forwarding is enabled */
+ if ((ie.gann_ttl - 1) < 1 && !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
+ return 0;
+ pgann.gann_flags = ie.gann_flags; /* Reserved */
+ pgann.gann_hopcount = ie.gann_hopcount + 1;
+ pgann.gann_ttl = ie.gann_ttl - 1;
+ IEEE80211_ADDR_COPY(pgann.gann_addr, ie.gann_addr);
+ pgann.gann_seq = ie.gann_seq;
+ pgann.gann_interval = ie.gann_interval;
+
+ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, ie.gann_addr,
+ "%s", "propagate GANN");
+
+ ieee80211_send_action(vap->iv_bss, IEEE80211_ACTION_CAT_MESH,
+ IEEE80211_ACTION_MESH_GANN, &pgann);
+
return 0;
}
static int
-mesh_send_action(struct ieee80211_node *ni, struct mbuf *m)
+mesh_send_action(struct ieee80211_node *ni,
+ const uint8_t sa[IEEE80211_ADDR_LEN],
+ const uint8_t da[IEEE80211_ADDR_LEN],
+ struct mbuf *m)
{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_bpf_params params;
+ struct ieee80211_frame *wh;
+ int ret;
+ KASSERT(ni != NULL, ("null node"));
+
+ if (vap->iv_state == IEEE80211_S_CAC) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
+ "block %s frame in CAC state", "Mesh action");
+ vap->iv_stats.is_tx_badstate++;
+ ieee80211_free_node(ni);
+ m_freem(m);
+ return EIO; /* XXX */
+ }
+
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ if (m == NULL) {
+ ieee80211_free_node(ni);
+ return ENOMEM;
+ }
+
+ IEEE80211_TX_LOCK(ic);
+ wh = mtod(m, struct ieee80211_frame *);
+ ieee80211_send_setup(ni, m,
+ IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
+ IEEE80211_NONQOS_TID, sa, da, sa);
+ m->m_flags |= M_ENCAP; /* mark encapsulated */
+
memset(¶ms, 0, sizeof(params));
params.ibp_pri = WME_AC_VO;
params.ibp_rate0 = ni->ni_txparms->mgmtrate;
- /* XXX ucast/mcast */
- params.ibp_try0 = ni->ni_txparms->maxretry;
+ if (IEEE80211_IS_MULTICAST(da))
+ params.ibp_try0 = 1;
+ else
+ params.ibp_try0 = ni->ni_txparms->maxretry;
params.ibp_power = ni->ni_txpower;
- return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
- ¶ms);
+
+ IEEE80211_NODE_STAT(ni, tx_mgmt);
+
+ ret = ieee80211_raw_output(vap, ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
@@ -1935,10 +2758,10 @@
ic->ic_headroom + sizeof(struct ieee80211_frame),
sizeof(uint16_t) /* action+category */
+ sizeof(uint16_t) /* capabilites */
- + 2 + IEEE80211_RATE_SIZE
- + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ + 2 + IEEE80211_RATE_SIZE
+ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ 2 + IEEE80211_MESHID_LEN
- + sizeof(struct ieee80211_meshconf_ie)
+ + sizeof(struct ieee80211_meshconf_ie)
+ sizeof(struct ieee80211_meshpeer_ie)
);
if (m != NULL) {
@@ -1961,10 +2784,10 @@
frm = ieee80211_add_xrates(frm, rs);
frm = ieee80211_add_meshid(frm, vap);
frm = ieee80211_add_meshconf(frm, vap);
- frm = ieee80211_add_meshpeer(frm, IEEE80211_MESH_PEER_LINK_OPEN,
+ frm = ieee80211_add_meshpeer(frm, IEEE80211_ACTION_MESHPEERING_OPEN,
args[0], 0, 0);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- return mesh_send_action(ni, m);
+ return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@@ -1998,10 +2821,10 @@
+ sizeof(uint16_t) /* capabilites */
+ sizeof(uint16_t) /* status code */
+ sizeof(uint16_t) /* AID */
- + 2 + IEEE80211_RATE_SIZE
- + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ + 2 + IEEE80211_RATE_SIZE
+ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ 2 + IEEE80211_MESHID_LEN
- + sizeof(struct ieee80211_meshconf_ie)
+ + sizeof(struct ieee80211_meshconf_ie)
+ sizeof(struct ieee80211_meshpeer_ie)
);
if (m != NULL) {
@@ -2029,10 +2852,10 @@
frm = ieee80211_add_meshid(frm, vap);
frm = ieee80211_add_meshconf(frm, vap);
frm = ieee80211_add_meshpeer(frm,
- IEEE80211_MESH_PEER_LINK_CONFIRM,
+ IEEE80211_ACTION_MESHPEERING_CONFIRM,
args[0], args[1], 0);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- return mesh_send_action(ni, m);
+ return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@@ -2064,7 +2887,7 @@
sizeof(uint16_t) /* action+category */
+ sizeof(uint16_t) /* reason code */
+ 2 + IEEE80211_MESHID_LEN
- + sizeof(struct ieee80211_meshpeer_ie)
+ + sizeof(struct ieee80211_meshpeer_ie)
);
if (m != NULL) {
/*
@@ -2071,19 +2894,17 @@
* mesh peer close action frame format:
* [1] category
* [1] action
- * [2] reason code
* [tlv] mesh id
* [tlv] mesh peer link mgmt
*/
*frm++ = category;
*frm++ = action;
- ADDSHORT(frm, args[2]); /* reason code */
frm = ieee80211_add_meshid(frm, vap);
frm = ieee80211_add_meshpeer(frm,
- IEEE80211_MESH_PEER_LINK_CLOSE,
+ IEEE80211_ACTION_MESHPEERING_CLOSE,
args[0], args[1], args[2]);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- return mesh_send_action(ni, m);
+ return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@@ -2092,17 +2913,23 @@
}
static int
-mesh_send_action_meshlink_request(struct ieee80211_node *ni,
+mesh_send_action_meshlmetric(struct ieee80211_node *ni,
int category, int action, void *arg0)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_meshlmetric_ie *ie = arg0;
struct mbuf *m;
uint8_t *frm;
- IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
- "%s", "send LINK METRIC REQUEST action");
-
+ if (ie->lm_flags & IEEE80211_MESH_LMETRIC_FLAGS_REQ) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ ni, "%s", "send LINK METRIC REQUEST action");
+ } else {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ ni, "send LINK METRIC REPLY action: metric 0x%x",
+ ie->lm_metric);
+ }
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
@@ -2110,18 +2937,22 @@
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
- sizeof(uint16_t) /* action+category */
+ sizeof(uint16_t) + /* action+category */
+ sizeof(struct ieee80211_meshlmetric_ie)
);
if (m != NULL) {
/*
- * mesh link metric request
+ * mesh link metric
* [1] category
* [1] action
+ * [tlv] mesh link metric
*/
*frm++ = category;
*frm++ = action;
+ frm = ieee80211_add_meshlmetric(frm,
+ ie->lm_flags, ie->lm_metric);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- return mesh_send_action(ni, m);
+ return mesh_send_action(ni, vap->iv_myaddr, ni->ni_macaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@@ -2130,18 +2961,15 @@
}
static int
-mesh_send_action_meshlink_reply(struct ieee80211_node *ni,
- int category, int action, void *args0)
+mesh_send_action_meshgate(struct ieee80211_node *ni,
+ int category, int action, void *arg0)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
- uint32_t *metric = args0;
+ struct ieee80211_meshgann_ie *ie = arg0;
struct mbuf *m;
uint8_t *frm;
- IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
- "send LINK METRIC REPLY action: metric 0x%x", *metric);
-
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
@@ -2149,21 +2977,21 @@
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
- sizeof(uint16_t) /* action+category */
- + sizeof(struct ieee80211_meshlmetric_ie)
+ sizeof(uint16_t) + /* action+category */
+ IEEE80211_MESHGANN_BASE_SZ
);
if (m != NULL) {
/*
- * mesh link metric reply
+ * mesh link metric
* [1] category
* [1] action
- * [tlv] mesh link metric
+ * [tlv] mesh gate annoucement
*/
*frm++ = category;
*frm++ = action;
- frm = ieee80211_add_meshlmetric(frm, *metric);
+ frm = ieee80211_add_meshgate(frm, ie);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
- return mesh_send_action(ni, m);
+ return mesh_send_action(ni, vap->iv_myaddr, broadcastaddr, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
@@ -2213,6 +3041,15 @@
callout_drain(&ni->ni_mltimer);
}
+static void
+mesh_peer_backoff_cb(void *arg)
+{
+ struct ieee80211_node *ni = (struct ieee80211_node *)arg;
+
+ /* After backoff timeout, try to peer automatically again. */
+ ni->ni_mlhcnt = 0;
+}
+
/*
* Mesh Peer Link Management FSM timeout handling.
*/
@@ -2236,7 +3073,7 @@
args[0] = ni->ni_mlpid;
args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_CLOSE, args);
ni->ni_mlrcnt = 0;
mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
@@ -2244,7 +3081,7 @@
} else {
args[0] = ni->ni_mlpid;
ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_CAT_SELF_PROT,
IEEE80211_ACTION_MESHPEERING_OPEN, args);
ni->ni_mlrcnt++;
mesh_peer_timeout_backoff(ni);
@@ -2251,21 +3088,20 @@
}
break;
case IEEE80211_NODE_MESH_CONFIRMRCV:
- if (ni->ni_mlrcnt == ieee80211_mesh_maxretries) {
- args[0] = ni->ni_mlpid;
- args[2] = IEEE80211_REASON_MESH_CONFIRM_TIMEOUT;
- ieee80211_send_action(ni,
- IEEE80211_ACTION_CAT_MESHPEERING,
- IEEE80211_ACTION_MESHPEERING_CLOSE, args);
- ni->ni_mlrcnt = 0;
- mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
- mesh_peer_timeout_setup(ni);
- } else {
- ni->ni_mlrcnt++;
- mesh_peer_timeout_setup(ni);
- }
+ args[0] = ni->ni_mlpid;
+ args[2] = IEEE80211_REASON_MESH_CONFIRM_TIMEOUT;
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_SELF_PROT,
+ IEEE80211_ACTION_MESHPEERING_CLOSE, args);
+ mesh_linkchange(ni, IEEE80211_NODE_MESH_HOLDING);
+ mesh_peer_timeout_setup(ni);
break;
case IEEE80211_NODE_MESH_HOLDING:
+ ni->ni_mlhcnt++;
+ if (ni->ni_mlhcnt >= ieee80211_mesh_maxholding)
+ callout_reset(&ni->ni_mlhtimer,
+ ieee80211_mesh_backofftimeout,
+ mesh_peer_backoff_cb, ni);
mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE);
break;
}
@@ -2290,7 +3126,6 @@
const struct ieee80211_meshconf_ie *meshconf =
(const struct ieee80211_meshconf_ie *) ie;
const struct ieee80211_mesh_state *ms = vap->iv_mesh;
- uint16_t cap;
if (meshconf == NULL)
return 1;
@@ -2324,10 +3159,8 @@
meshconf->conf_pselid);
return 1;
}
- /* NB: conf_cap is only read correctly here */
- cap = LE_READ_2(&meshconf->conf_cap);
/* Not accepting peers */
- if (!(cap & IEEE80211_MESHCONF_CAP_AP)) {
+ if (!(meshconf->conf_cap & IEEE80211_MESHCONF_CAP_AP)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH,
"not accepting peers: 0x%x\n", meshconf->conf_cap);
return 1;
@@ -2342,22 +3175,31 @@
const struct ieee80211_meshpeer_ie *meshpeer =
(const struct ieee80211_meshpeer_ie *) ie;
- if (meshpeer == NULL || meshpeer->peer_len < 6 ||
- meshpeer->peer_len > 10)
+ if (meshpeer == NULL ||
+ meshpeer->peer_len < IEEE80211_MPM_BASE_SZ ||
+ meshpeer->peer_len > IEEE80211_MPM_MAX_SZ)
return 1;
+ if (meshpeer->peer_proto != IEEE80211_MPPID_MPM) {
+ IEEE80211_DPRINTF(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ "Only MPM protocol is supported (proto: 0x%02X)",
+ meshpeer->peer_proto);
+ return 1;
+ }
switch (subtype) {
- case IEEE80211_MESH_PEER_LINK_OPEN:
- if (meshpeer->peer_len != 6)
+ case IEEE80211_ACTION_MESHPEERING_OPEN:
+ if (meshpeer->peer_len != IEEE80211_MPM_BASE_SZ)
return 1;
break;
- case IEEE80211_MESH_PEER_LINK_CONFIRM:
- if (meshpeer->peer_len != 8)
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ if (meshpeer->peer_len != IEEE80211_MPM_BASE_SZ + 2)
return 1;
break;
- case IEEE80211_MESH_PEER_LINK_CLOSE:
- if (meshpeer->peer_len < 8)
+ case IEEE80211_ACTION_MESHPEERING_CLOSE:
+ if (meshpeer->peer_len < IEEE80211_MPM_BASE_SZ + 2)
return 1;
- if (meshpeer->peer_len == 8 && meshpeer->peer_linkid != 0)
+ if (meshpeer->peer_len == (IEEE80211_MPM_BASE_SZ + 2) &&
+ meshpeer->peer_linkid != 0)
return 1;
if (meshpeer->peer_rcode == 0)
return 1;
@@ -2396,7 +3238,7 @@
KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap"));
*frm++ = IEEE80211_ELEMID_MESHCONF;
- *frm++ = sizeof(struct ieee80211_meshconf_ie) - 2;
+ *frm++ = IEEE80211_MESH_CONF_SZ;
*frm++ = ms->ms_ppath->mpp_ie; /* path selection */
*frm++ = ms->ms_pmetric->mpm_ie; /* link metric */
*frm++ = IEEE80211_MESHCONF_CC_DISABLED;
@@ -2403,9 +3245,10 @@
*frm++ = IEEE80211_MESHCONF_SYNC_NEIGHOFF;
*frm++ = IEEE80211_MESHCONF_AUTH_DISABLED;
/* NB: set the number of neighbors before the rest */
- *frm = (ms->ms_neighbors > 15 ? 15 : ms->ms_neighbors) << 1;
- if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
- *frm |= IEEE80211_MESHCONF_FORM_MP;
+ *frm = (ms->ms_neighbors > IEEE80211_MESH_MAX_NEIGHBORS ?
+ IEEE80211_MESH_MAX_NEIGHBORS : ms->ms_neighbors) << 1;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_GATE)
+ *frm |= IEEE80211_MESHCONF_FORM_GATE;
frm += 1;
caps = 0;
if (ms->ms_flags & IEEE80211_MESHFLAGS_AP)
@@ -2412,7 +3255,7 @@
caps |= IEEE80211_MESHCONF_CAP_AP;
if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)
caps |= IEEE80211_MESHCONF_CAP_FWRD;
- ADDSHORT(frm, caps);
+ *frm++ = caps;
return frm;
}
@@ -2423,34 +3266,29 @@
ieee80211_add_meshpeer(uint8_t *frm, uint8_t subtype, uint16_t localid,
uint16_t peerid, uint16_t reason)
{
- /* XXX change for AH */
- static const uint8_t meshpeerproto[4] = IEEE80211_MESH_PEER_PROTO;
KASSERT(localid != 0, ("localid == 0"));
*frm++ = IEEE80211_ELEMID_MESHPEER;
switch (subtype) {
- case IEEE80211_MESH_PEER_LINK_OPEN:
- *frm++ = 6; /* length */
- memcpy(frm, meshpeerproto, 4);
- frm += 4;
- ADDSHORT(frm, localid); /* local ID */
+ case IEEE80211_ACTION_MESHPEERING_OPEN:
+ *frm++ = IEEE80211_MPM_BASE_SZ; /* length */
+ ADDSHORT(frm, IEEE80211_MPPID_MPM); /* proto */
+ ADDSHORT(frm, localid); /* local ID */
break;
- case IEEE80211_MESH_PEER_LINK_CONFIRM:
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
KASSERT(peerid != 0, ("sending peer confirm without peer id"));
- *frm++ = 8; /* length */
- memcpy(frm, meshpeerproto, 4);
- frm += 4;
- ADDSHORT(frm, localid); /* local ID */
- ADDSHORT(frm, peerid); /* peer ID */
+ *frm++ = IEEE80211_MPM_BASE_SZ + 2; /* length */
+ ADDSHORT(frm, IEEE80211_MPPID_MPM); /* proto */
+ ADDSHORT(frm, localid); /* local ID */
+ ADDSHORT(frm, peerid); /* peer ID */
break;
- case IEEE80211_MESH_PEER_LINK_CLOSE:
+ case IEEE80211_ACTION_MESHPEERING_CLOSE:
if (peerid)
- *frm++ = 10; /* length */
+ *frm++ = IEEE80211_MPM_MAX_SZ; /* length */
else
- *frm++ = 8; /* length */
- memcpy(frm, meshpeerproto, 4);
- frm += 4;
+ *frm++ = IEEE80211_MPM_BASE_SZ + 2; /* length */
+ ADDSHORT(frm, IEEE80211_MPPID_MPM); /* proto */
ADDSHORT(frm, localid); /* local ID */
if (peerid)
ADDSHORT(frm, peerid); /* peer ID */
@@ -2470,7 +3308,7 @@
*/
#define IEEE80211_MESH_MAXOVERHEAD \
(sizeof(struct ieee80211_qosframe_addr4) \
- + sizeof(struct ieee80211_meshcntl_ae11) \
+ + sizeof(struct ieee80211_meshcntl_ae10) \
+ sizeof(struct llc) \
+ IEEE80211_ADDR_LEN \
+ IEEE80211_WEP_IVLEN \
@@ -2509,13 +3347,32 @@
* Add a Mesh Link Metric report IE to a frame.
*/
uint8_t *
-ieee80211_add_meshlmetric(uint8_t *frm, uint32_t metric)
+ieee80211_add_meshlmetric(uint8_t *frm, uint8_t flags, uint32_t metric)
{
*frm++ = IEEE80211_ELEMID_MESHLINK;
- *frm++ = 4;
+ *frm++ = 5;
+ *frm++ = flags;
ADDWORD(frm, metric);
return frm;
}
+
+/*
+ * Add a Mesh Gate Announcement IE to a frame.
+ */
+uint8_t *
+ieee80211_add_meshgate(uint8_t *frm, struct ieee80211_meshgann_ie *ie)
+{
+ *frm++ = IEEE80211_ELEMID_MESHGANN; /* ie */
+ *frm++ = IEEE80211_MESHGANN_BASE_SZ; /* len */
+ *frm++ = ie->gann_flags;
+ *frm++ = ie->gann_hopcount;
+ *frm++ = ie->gann_ttl;
+ IEEE80211_ADDR_COPY(frm, ie->gann_addr);
+ frm += 6;
+ ADDWORD(frm, ie->gann_seq);
+ ADDSHORT(frm, ie->gann_interval);
+ return frm;
+}
#undef ADDSHORT
#undef ADDWORD
@@ -2526,7 +3383,8 @@
ieee80211_mesh_node_init(struct ieee80211vap *vap, struct ieee80211_node *ni)
{
ni->ni_flags |= IEEE80211_NODE_QOS;
- callout_init(&ni->ni_mltimer, CALLOUT_MPSAFE);
+ callout_init(&ni->ni_mltimer, 1);
+ callout_init(&ni->ni_mlhtimer, 1);
}
/*
@@ -2539,6 +3397,7 @@
struct ieee80211_mesh_state *ms = vap->iv_mesh;
callout_drain(&ni->ni_mltimer);
+ callout_drain(&ni->ni_mlhtimer);
/* NB: short-circuit callbacks after mesh_vdetach */
if (vap->iv_mesh != NULL)
ms->ms_ppath->mpp_peerdown(ni);
@@ -2601,6 +3460,9 @@
case IEEE80211_IOC_MESH_FWRD:
ireq->i_val = (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) != 0;
break;
+ case IEEE80211_IOC_MESH_GATE:
+ ireq->i_val = (ms->ms_flags & IEEE80211_MESHFLAGS_GATE) != 0;
+ break;
case IEEE80211_IOC_MESH_TTL:
ireq->i_val = ms->ms_ttl;
break;
@@ -2629,7 +3491,6 @@
break;
imr = (struct ieee80211req_mesh_route *)
(p + off);
- imr->imr_flags = rt->rt_flags;
IEEE80211_ADDR_COPY(imr->imr_dest,
rt->rt_dest);
IEEE80211_ADDR_COPY(imr->imr_nexthop,
@@ -2636,8 +3497,10 @@
rt->rt_nexthop);
imr->imr_metric = rt->rt_metric;
imr->imr_nhops = rt->rt_nhops;
- imr->imr_lifetime = rt->rt_lifetime;
+ imr->imr_lifetime =
+ ieee80211_mesh_rt_update(rt, 0);
imr->imr_lastmseq = rt->rt_lastmseq;
+ imr->imr_flags = rt->rt_flags; /* last */
off += sizeof(*imr);
}
MESH_RT_UNLOCK(ms);
@@ -2714,7 +3577,14 @@
ms->ms_flags |= IEEE80211_MESHFLAGS_FWD;
else
ms->ms_flags &= ~IEEE80211_MESHFLAGS_FWD;
+ mesh_gatemode_setup(vap);
break;
+ case IEEE80211_IOC_MESH_GATE:
+ if (ireq->i_val)
+ ms->ms_flags |= IEEE80211_MESHFLAGS_GATE;
+ else
+ ms->ms_flags &= ~IEEE80211_MESHFLAGS_GATE;
+ break;
case IEEE80211_IOC_MESH_TTL:
ms->ms_ttl = (uint8_t) ireq->i_val;
break;
Modified: trunk/sys/net80211/ieee80211_mesh.h
===================================================================
--- trunk/sys/net80211/ieee80211_mesh.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_mesh.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 The FreeBSD Foundation
* All rights reserved.
@@ -26,12 +27,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_mesh.h 246512 2013-02-07 21:26:40Z monthadar $
*/
#ifndef _NET80211_IEEE80211_MESH_H_
#define _NET80211_IEEE80211_MESH_H_
#define IEEE80211_MESH_DEFAULT_TTL 31
+#define IEEE80211_MESH_MAX_NEIGHBORS 15
/*
* NB: all structures are __packed so sizeof works on arm, et. al.
@@ -40,6 +42,7 @@
* 802.11s Information Elements.
*/
/* Mesh Configuration */
+#define IEEE80211_MESH_CONF_SZ (7)
struct ieee80211_meshconf_ie {
uint8_t conf_ie; /* IEEE80211_ELEMID_MESHCONF */
uint8_t conf_len;
@@ -49,31 +52,66 @@
uint8_t conf_syncid; /* Sync. Protocol ID */
uint8_t conf_authid; /* Auth. Protocol ID */
uint8_t conf_form; /* Formation Information */
- uint16_t conf_cap;
+ uint8_t conf_cap;
} __packed;
/* Hybrid Wireless Mesh Protocol */
-#define IEEE80211_MESHCONF_PATH_HWMP 0x00
+enum {
+ /* 0 reserved */
+ IEEE80211_MESHCONF_PATH_HWMP = 1,
+ /* 2-254 reserved */
+ IEEE80211_MESHCONF_PATH_VENDOR = 255,
+};
+
/* Airtime Link Metric */
-#define IEEE80211_MESHCONF_METRIC_AIRTIME 0x00
+enum {
+ /* 0 reserved */
+ IEEE80211_MESHCONF_METRIC_AIRTIME = 1,
+ /* 2-254 reserved */
+ IEEE80211_MESHCONF_METRIC_VENDOR = 255,
+};
+
/* Congestion Control */
-#define IEEE80211_MESHCONF_CC_DISABLED 0x00
-#define IEEE80211_MESHCONF_CC_SIG 0x01
+enum {
+ IEEE80211_MESHCONF_CC_DISABLED = 0,
+ IEEE80211_MESHCONF_CC_SIG = 1,
+ /* 2-254 reserved */
+ IEEE80211_MESHCONF_CC_VENDOR = 255,
+};
+
/* Neighbour Offset */
-#define IEEE80211_MESHCONF_SYNC_NEIGHOFF 0x00
-#define IEEE80211_MESHCONF_AUTH_DISABLED 0x00
-/* Simultaneous Authenticaction of Equals */
-#define IEEE80211_MESHCONF_AUTH_SAE 0x01
-#define IEEE80211_MESHCONF_FORM_MP 0x01 /* Connected to Portal */
-#define IEEE80211_MESHCONF_FORM_NNEIGH_MASK 0x04 /* Number of Neighbours */
+enum {
+ /* 0 reserved */
+ IEEE80211_MESHCONF_SYNC_NEIGHOFF = 1,
+ /* 2-254 rserved */
+ IEEE80211_MESHCONF_SYNC_VENDOR = 255,
+};
+
+/* Authentication Protocol Identifier */
+enum {
+
+ IEEE80211_MESHCONF_AUTH_DISABLED = 0,
+ /* Simultaneous Authenticaction of Equals */
+ IEEE80211_MESHCONF_AUTH_SEA = 1,
+ IEEE80211_MESHCONF_AUTH_8021X = 2, /* IEEE 802.1X */
+ /* 3-254 reserved */
+ IEEE80211_MESHCONF_AUTH_VENDOR = 255,
+};
+
+/* Mesh Formation Info */
+#define IEEE80211_MESHCONF_FORM_GATE 0x01 /* Connected to Gate */
+#define IEEE80211_MESHCONF_FORM_NNEIGH_MASK 0x7E /* Number of Neighbours */
+#define IEEE80211_MESHCONF_FORM_SA 0xF0 /* indicating 802.1X auth */
+
+/* Mesh Capability */
#define IEEE80211_MESHCONF_CAP_AP 0x01 /* Accepting Peers */
#define IEEE80211_MESHCONF_CAP_MCCAS 0x02 /* MCCA supported */
#define IEEE80211_MESHCONF_CAP_MCCAE 0x04 /* MCCA enabled */
#define IEEE80211_MESHCONF_CAP_FWRD 0x08 /* forwarding enabled */
#define IEEE80211_MESHCONF_CAP_BTR 0x10 /* Beacon Timing Report Enab */
-#define IEEE80211_MESHCONF_CAP_TBTTA 0x20 /* TBTT Adj. Enabled */
-#define IEEE80211_MESHCONF_CAP_TBTT 0x40 /* TBTT Adjusting */
-#define IEEE80211_MESHCONF_CAP_PSL 0x80 /* Power Save Level */
+#define IEEE80211_MESHCONF_CAP_TBTT 0x20 /* TBTT Adjusting */
+#define IEEE80211_MESHCONF_CAP_PSL 0x40 /* Power Save Level */
+/* 0x80 reserved */
/* Mesh Identifier */
struct ieee80211_meshid_ie {
@@ -83,8 +121,14 @@
/* Link Metric Report */
struct ieee80211_meshlmetric_ie {
- uint8_t lm_ie; /* IEEE80211_ELEMID_MESHLINK */
+ uint8_t lm_ie; /* IEEE80211_ACTION_MESH_LMETRIC */
uint8_t lm_len;
+ uint8_t lm_flags;
+#define IEEE80211_MESH_LMETRIC_FLAGS_REQ 0x01 /* Request */
+ /*
+ * XXX: this field should be variable in size and depend on
+ * the active active path selection metric identifier
+ */
uint32_t lm_metric;
#define IEEE80211_MESHLMETRIC_INITIALVAL 0
} __packed;
@@ -98,32 +142,24 @@
} __packed;
/* Peer Link Management */
+#define IEEE80211_MPM_BASE_SZ (4)
+#define IEEE80211_MPM_MAX_SZ (8)
struct ieee80211_meshpeer_ie {
uint8_t peer_ie; /* IEEE80211_ELEMID_MESHPEER */
uint8_t peer_len;
- uint8_t peer_proto[4]; /* Peer Management Protocol */
+ uint16_t peer_proto; /* Peer Management Protocol */
uint16_t peer_llinkid; /* Local Link ID */
uint16_t peer_linkid; /* Peer Link ID */
uint16_t peer_rcode;
} __packed;
+/* Mesh Peering Protocol Identifier field value */
enum {
- IEEE80211_MESH_PEER_LINK_OPEN = 0,
- IEEE80211_MESH_PEER_LINK_CONFIRM = 1,
- IEEE80211_MESH_PEER_LINK_CLOSE = 2,
- /* values 3-255 are reserved */
+ IEEE80211_MPPID_MPM = 0, /* Mesh peering management */
+ IEEE80211_MPPID_AUTH_MPM = 1, /* Auth. mesh peering exchange */
+ /* 2-65535 reserved */
};
-/* Mesh Peering Management Protocol */
-#define IEEE80211_MESH_PEER_PROTO_OUI 0x00, 0x0f, 0xac
-#define IEEE80211_MESH_PEER_PROTO_VALUE 0x2a
-#define IEEE80211_MESH_PEER_PROTO { IEEE80211_MESH_PEER_PROTO_OUI, \
- IEEE80211_MESH_PEER_PROTO_VALUE }
-/* Abbreviated Handshake Protocol */
-#define IEEE80211_MESH_PEER_PROTO_AH_OUI 0x00, 0x0f, 0xac
-#define IEEE80211_MESH_PEER_PROTO_AH_VALUE 0x2b
-#define IEEE80211_MESH_PEER_PROTO_AH { IEEE80211_MESH_PEER_PROTO_AH_OUI, \
- IEEE80211_MESH_PEER_PROTO_AH_VALUE }
#ifdef notyet
/* Mesh Channel Switch Annoucement */
struct ieee80211_meshcsa_ie {
@@ -158,37 +194,50 @@
} __packed;
#endif
-/* 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 */
+/* Gate (GANN) Annoucement */
+/*
+ * NB: these macros used for the length in the IEs does not include 2 bytes
+ * for _ie and _len fields as is defined by the standard.
+ */
+#define IEEE80211_MESHGANN_BASE_SZ (15)
+struct ieee80211_meshgann_ie {
+ uint8_t gann_ie; /* IEEE80211_ELEMID_MESHGANN */
+ uint8_t gann_len;
+ uint8_t gann_flags;
+ uint8_t gann_hopcount;
+ uint8_t gann_ttl;
+ uint8_t gann_addr[IEEE80211_ADDR_LEN];
+ uint32_t gann_seq; /* GANN Sequence Number */
+ uint16_t gann_interval; /* GANN Interval */
} __packed;
/* Root (MP) Annoucement */
+#define IEEE80211_MESHRANN_BASE_SZ (21)
struct ieee80211_meshrann_ie {
uint8_t rann_ie; /* IEEE80211_ELEMID_MESHRANN */
uint8_t rann_len;
uint8_t rann_flags;
-#define IEEE80211_MESHRANN_FLAGS_PR 0x01 /* Portal Role */
+#define IEEE80211_MESHRANN_FLAGS_GATE 0x01 /* Mesh Gate */
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_interval;
uint32_t rann_metric;
} __packed;
/* Mesh Path Request */
+#define IEEE80211_MESHPREQ_BASE_SZ (26)
+#define IEEE80211_MESHPREQ_BASE_SZ_AE (32)
+#define IEEE80211_MESHPREQ_TRGT_SZ (11)
+#define IEEE80211_MESHPREQ_TCNT_OFFSET (27)
+#define IEEE80211_MESHPREQ_TCNT_OFFSET_AE (33)
struct ieee80211_meshpreq_ie {
uint8_t preq_ie; /* IEEE80211_ELEMID_MESHPREQ */
uint8_t preq_len;
uint8_t preq_flags;
-#define IEEE80211_MESHPREQ_FLAGS_PR 0x01 /* Portal Role */
-#define IEEE80211_MESHPREQ_FLAGS_AM 0x02 /* 0 = ucast / 1 = bcast */
+#define IEEE80211_MESHPREQ_FLAGS_GATE 0x01 /* Mesh Gate */
+#define IEEE80211_MESHPREQ_FLAGS_AM 0x02 /* 0 = bcast / 1 = ucast */
#define IEEE80211_MESHPREQ_FLAGS_PP 0x04 /* Proactive PREP */
#define IEEE80211_MESHPREQ_FLAGS_AE 0x40 /* Address Extension */
uint8_t preq_hopcount;
@@ -196,7 +245,8 @@
uint32_t preq_id;
uint8_t preq_origaddr[IEEE80211_ADDR_LEN];
uint32_t preq_origseq; /* HWMP Sequence Number */
- /* NB: may have Originator Proxied Address */
+ /* NB: may have Originator External Address */
+ uint8_t preq_orig_ext_addr[IEEE80211_ADDR_LEN];
uint32_t preq_lifetime;
uint32_t preq_metric;
uint8_t preq_tcount; /* target count */
@@ -203,7 +253,6 @@
struct {
uint8_t target_flags;
#define IEEE80211_MESHPREQ_TFLAGS_TO 0x01 /* Target Only */
-#define IEEE80211_MESHPREQ_TFLAGS_RF 0x02 /* Reply and Forward */
#define IEEE80211_MESHPREQ_TFLAGS_USN 0x04 /* Unknown HWMP seq number */
uint8_t target_addr[IEEE80211_ADDR_LEN];
uint32_t target_seq; /* HWMP Sequence Number */
@@ -211,15 +260,19 @@
} __packed;
/* Mesh Path Reply */
+#define IEEE80211_MESHPREP_BASE_SZ (31)
+#define IEEE80211_MESHPREP_BASE_SZ_AE (37)
struct ieee80211_meshprep_ie {
uint8_t prep_ie; /* IEEE80211_ELEMID_MESHPREP */
uint8_t prep_len;
uint8_t prep_flags;
+#define IEEE80211_MESHPREP_FLAGS_AE 0x40 /* Address Extension */
uint8_t prep_hopcount;
uint8_t prep_ttl;
uint8_t prep_targetaddr[IEEE80211_ADDR_LEN];
uint32_t prep_targetseq;
- /* NB: May have Target Proxied Address */
+ /* NB: May have Target External Address */
+ uint8_t prep_target_ext_addr[IEEE80211_ADDR_LEN];
uint32_t prep_lifetime;
uint32_t prep_metric;
uint8_t prep_origaddr[IEEE80211_ADDR_LEN];
@@ -227,6 +280,11 @@
} __packed;
/* Mesh Path Error */
+#define IEEE80211_MESHPERR_MAXDEST (19)
+#define IEEE80211_MESHPERR_NDEST_OFFSET (3)
+#define IEEE80211_MESHPERR_BASE_SZ (2)
+#define IEEE80211_MESHPERR_DEST_SZ (13)
+#define IEEE80211_MESHPERR_DEST_SZ_AE (19)
struct ieee80211_meshperr_ie {
uint8_t perr_ie; /* IEEE80211_ELEMID_MESHPERR */
uint8_t perr_len;
@@ -234,10 +292,13 @@
uint8_t perr_ndests; /* Number of Destinations */
struct {
uint8_t dest_flags;
-#define IEEE80211_MESHPERR_DFLAGS_USN 0x01
-#define IEEE80211_MESHPERR_DFLAGS_RC 0x02
+#define IEEE80211_MESHPERR_DFLAGS_USN 0x01 /* XXX: not part of standard */
+#define IEEE80211_MESHPERR_DFLAGS_RC 0x02 /* XXX: not part of standard */
+#define IEEE80211_MESHPERR_FLAGS_AE 0x40 /* Address Extension */
uint8_t dest_addr[IEEE80211_ADDR_LEN];
uint32_t dest_seq; /* HWMP Sequence Number */
+ /* NB: May have Destination External Address */
+ uint8_t dest_ext_addr[IEEE80211_ADDR_LEN];
uint16_t dest_rcode;
} __packed perr_dests[1]; /* NB: variable size */
} __packed;
@@ -269,10 +330,9 @@
/*
* 802.11s Action Frames
+ * XXX: these are wrong, and some of them should be
+ * under MESH category while PROXY is under MULTIHOP category.
*/
-#define IEEE80211_ACTION_CAT_MESHPEERING 30 /* XXX Linux */
-#define IEEE80211_ACTION_CAT_MESHLMETRIC 13
-#define IEEE80211_ACTION_CAT_MESHPATH 32 /* XXX Linux */
#define IEEE80211_ACTION_CAT_INTERWORK 15
#define IEEE80211_ACTION_CAT_RESOURCE 16
#define IEEE80211_ACTION_CAT_PROXY 17
@@ -281,38 +341,32 @@
* Mesh Peering Action codes.
*/
enum {
- IEEE80211_ACTION_MESHPEERING_OPEN = 0,
- IEEE80211_ACTION_MESHPEERING_CONFIRM = 1,
- IEEE80211_ACTION_MESHPEERING_CLOSE = 2,
- /* 3-255 reserved */
+ /* 0 reserved */
+ IEEE80211_ACTION_MESHPEERING_OPEN = 1,
+ IEEE80211_ACTION_MESHPEERING_CONFIRM = 2,
+ IEEE80211_ACTION_MESHPEERING_CLOSE = 3,
+ /* 4-255 reserved */
};
/*
- * Mesh Path Selection Action code.
+ * Mesh Action code.
*/
enum {
- IEEE80211_ACTION_MESHPATH_SEL = 0,
- /* 1-255 reserved */
+ IEEE80211_ACTION_MESH_LMETRIC = 0, /* Mesh Link Metric Report */
+ IEEE80211_ACTION_MESH_HWMP = 1, /* HWMP Mesh Path Selection */
+ IEEE80211_ACTION_MESH_GANN = 2, /* Gate Announcement */
+ IEEE80211_ACTION_MESH_CC = 3, /* Congestion Control */
+ IEEE80211_ACTION_MESH_MCCA_SREQ = 4, /* MCCA Setup Request */
+ IEEE80211_ACTION_MESH_MCCA_SREP = 5, /* MCCA Setup Reply */
+ IEEE80211_ACTION_MESH_MCCA_AREQ = 6, /* MCCA Advertisement Req. */
+ IEEE80211_ACTION_MESH_MCCA_ADVER =7, /* MCCA Advertisement */
+ IEEE80211_ACTION_MESH_MCCA_TRDOWN = 8, /* MCCA Teardown */
+ IEEE80211_ACTION_MESH_TBTT_REQ = 9, /* TBTT Adjustment Request */
+ IEEE80211_ACTION_MESH_TBTT_RES = 10, /* TBTT Adjustment Response */
+ /* 11-255 reserved */
};
/*
- * Mesh Link Metric Action codes.
- */
-enum {
- IEEE80211_ACTION_MESHLMETRIC_REQ = 0, /* Link Metric Request */
- IEEE80211_ACTION_MESHLMETRIC_REP = 1, /* Link Metric Report */
- /* 2-255 reserved */
-};
-
-/*
- * Mesh Portal Annoucement Action codes.
- */
-enum {
- IEEE80211_ACTION_MESHPANN = 0,
- /* 1-255 reserved */
-};
-
-/*
* Different mesh control structures based on the AE
* (Address Extension) bits.
*/
@@ -334,37 +388,67 @@
uint8_t mc_flags; /* Address Extension 10 */
uint8_t mc_ttl; /* TTL */
uint8_t mc_seq[4]; /* Sequence No. */
- uint8_t mc_addr4[IEEE80211_ADDR_LEN];
uint8_t mc_addr5[IEEE80211_ADDR_LEN];
-} __packed;
-
-struct ieee80211_meshcntl_ae11 {
- uint8_t mc_flags; /* Address Extension 11 */
- uint8_t mc_ttl; /* TTL */
- uint8_t mc_seq[4]; /* Sequence No. */
- uint8_t mc_addr4[IEEE80211_ADDR_LEN];
- uint8_t mc_addr5[IEEE80211_ADDR_LEN];
uint8_t mc_addr6[IEEE80211_ADDR_LEN];
} __packed;
+#define IEEE80211_MESH_AE_MASK 0x03
+enum {
+ IEEE80211_MESH_AE_00 = 0, /* MC has no AE subfield */
+ IEEE80211_MESH_AE_01 = 1, /* MC contain addr4 */
+ IEEE80211_MESH_AE_10 = 2, /* MC contain addr5 & addr6 */
+ IEEE80211_MESH_AE_11 = 3, /* RESERVED */
+};
+
#ifdef _KERNEL
+MALLOC_DECLARE(M_80211_MESH_PREQ);
+MALLOC_DECLARE(M_80211_MESH_PREP);
+MALLOC_DECLARE(M_80211_MESH_PERR);
+
MALLOC_DECLARE(M_80211_MESH_RT);
+MALLOC_DECLARE(M_80211_MESH_GT_RT);
+/*
+ * Basic forwarding information:
+ * o Destination MAC
+ * o Next-hop MAC
+ * o Precursor list (not implemented yet)
+ * o Path timeout
+ * The rest is part of the active Mesh path selection protocol.
+ * XXX: to be moved out later.
+ */
struct ieee80211_mesh_route {
TAILQ_ENTRY(ieee80211_mesh_route) rt_next;
- int rt_crtime; /* creation time */
+ struct ieee80211vap *rt_vap;
+ struct mtx rt_lock; /* fine grained route lock */
+ struct callout rt_discovery; /* discovery timeout */
+ int rt_updtime; /* last update time */
uint8_t rt_dest[IEEE80211_ADDR_LEN];
+ uint8_t rt_mesh_gate[IEEE80211_ADDR_LEN]; /* meshDA */
uint8_t rt_nexthop[IEEE80211_ADDR_LEN];
uint32_t rt_metric; /* path metric */
uint16_t rt_nhops; /* number of hops */
uint16_t rt_flags;
-#define IEEE80211_MESHRT_FLAGS_VALID 0x01 /* patch discovery complete */
-#define IEEE80211_MESHRT_FLAGS_PROXY 0x02 /* proxy entry */
- uint32_t rt_lifetime;
+#define IEEE80211_MESHRT_FLAGS_DISCOVER 0x01 /* path discovery */
+#define IEEE80211_MESHRT_FLAGS_VALID 0x02 /* path discovery complete */
+#define IEEE80211_MESHRT_FLAGS_PROXY 0x04 /* proxy entry */
+#define IEEE80211_MESHRT_FLAGS_GATE 0x08 /* mesh gate entry */
+ uint32_t rt_lifetime; /* route timeout */
uint32_t rt_lastmseq; /* last seq# seen dest */
+ uint32_t rt_ext_seq; /* proxy seq number */
void *rt_priv; /* private data */
};
#define IEEE80211_MESH_ROUTE_PRIV(rt, cast) ((cast *)rt->rt_priv)
+/*
+ * Stored information about known mesh gates.
+ */
+struct ieee80211_mesh_gate_route {
+ TAILQ_ENTRY(ieee80211_mesh_gate_route) gr_next;
+ uint8_t gr_addr[IEEE80211_ADDR_LEN];
+ uint32_t gr_lastseq;
+ struct ieee80211_mesh_route *gr_route;
+};
+
#define IEEE80211_MESH_PROTO_DSZ 12 /* description size */
/*
* Mesh Path Selection Protocol.
@@ -379,6 +463,9 @@
const uint8_t [IEEE80211_ADDR_LEN],
struct mbuf *);
void (*mpp_peerdown)(struct ieee80211_node *);
+ void (*mpp_senderror)(struct ieee80211vap *,
+ const uint8_t [IEEE80211_ADDR_LEN],
+ struct ieee80211_mesh_route *, int);
void (*mpp_vattach)(struct ieee80211vap *);
void (*mpp_vdetach)(struct ieee80211vap *);
int (*mpp_newstate)(struct ieee80211vap *,
@@ -425,11 +512,15 @@
uint16_t ms_neighbors;
uint8_t ms_ttl; /* mesh ttl set in packets */
#define IEEE80211_MESHFLAGS_AP 0x01 /* accept peers */
-#define IEEE80211_MESHFLAGS_PORTAL 0x02 /* mesh portal role */
+#define IEEE80211_MESHFLAGS_GATE 0x02 /* mesh gate role */
#define IEEE80211_MESHFLAGS_FWD 0x04 /* forward packets */
+#define IEEE80211_MESHFLAGS_ROOT 0x08 /* configured as root */
uint8_t ms_flags;
struct mtx ms_rt_lock;
struct callout ms_cleantimer;
+ struct callout ms_gatetimer;
+ ieee80211_mesh_seq ms_gateseq;
+ TAILQ_HEAD(, ieee80211_mesh_gate_route) ms_known_gates;
TAILQ_HEAD(, ieee80211_mesh_route) ms_routes;
struct ieee80211_mesh_proto_metric *ms_pmetric;
struct ieee80211_mesh_proto_path *ms_ppath;
@@ -448,6 +539,7 @@
void ieee80211_mesh_rt_flush(struct ieee80211vap *);
void ieee80211_mesh_rt_flush_peer(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
+int ieee80211_mesh_rt_update(struct ieee80211_mesh_route *rt, int);
void ieee80211_mesh_proxy_check(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
@@ -460,7 +552,9 @@
uint8_t * ieee80211_add_meshconf(uint8_t *, struct ieee80211vap *);
uint8_t * ieee80211_add_meshpeer(uint8_t *, uint8_t, uint16_t, uint16_t,
uint16_t);
-uint8_t * ieee80211_add_meshlmetric(uint8_t *, uint32_t);
+uint8_t * ieee80211_add_meshlmetric(uint8_t *, uint8_t, uint32_t);
+uint8_t * ieee80211_add_meshgate(uint8_t *,
+ struct ieee80211_meshgann_ie *);
void ieee80211_mesh_node_init(struct ieee80211vap *,
struct ieee80211_node *);
@@ -473,6 +567,14 @@
const struct ieee80211_scanparams *);
void ieee80211_mesh_update_beacon(struct ieee80211vap *,
struct ieee80211_beacon_offsets *);
+struct ieee80211_mesh_gate_route *
+ ieee80211_mesh_mark_gate(struct ieee80211vap *,
+ const uint8_t *, struct ieee80211_mesh_route *);
+void ieee80211_mesh_forward_to_gates(struct ieee80211vap *,
+ struct ieee80211_mesh_route *);
+struct ieee80211_node *
+ ieee80211_mesh_find_txnode(struct ieee80211vap *,
+ const uint8_t [IEEE80211_ADDR_LEN]);
/*
* Return non-zero if proxy operation is enabled.
@@ -482,7 +584,7 @@
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
return (ms->ms_flags &
- (IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_PORTAL)) != 0;
+ (IEEE80211_MESHFLAGS_AP | IEEE80211_MESHFLAGS_GATE)) != 0;
}
/*
Modified: trunk/sys/net80211/ieee80211_monitor.c
===================================================================
--- trunk/sys/net80211/ieee80211_monitor.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_monitor.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_monitor.c 193287 2009-06-02 00:04:10Z sam $");
#endif
/*
Modified: trunk/sys/net80211/ieee80211_monitor.h
===================================================================
--- trunk/sys/net80211/ieee80211_monitor.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_monitor.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_monitor.h 178354 2008-04-20 20:35:46Z sam $
*/
#ifndef _NET80211_IEEE80211_MONITOR_H_
#define _NET80211_IEEE80211_MONITOR_H_
Modified: trunk/sys/net80211/ieee80211_node.c
===================================================================
--- trunk/sys/net80211/ieee80211_node.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_node.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_node.c 314667 2017-03-04 13:03:31Z avg $");
#include "opt_wlan.h"
@@ -111,7 +112,7 @@
"802.11 staging q");
ieee80211_node_table_init(ic, &ic->ic_sta, "station",
IEEE80211_INACT_INIT, ic->ic_max_keyix);
- callout_init(&ic->ic_inact, CALLOUT_MPSAFE);
+ callout_init(&ic->ic_inact, 1);
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
ieee80211_node_timeout, ic);
@@ -685,6 +686,14 @@
ieee80211_runtask(ic, &ic->ic_chan_task);
}
+void
+ieee80211_update_chw(struct ieee80211com *ic)
+{
+
+ ieee80211_setupcurchan(ic, ic->ic_curchan);
+ ieee80211_runtask(ic, &ic->ic_chw_task);
+}
+
/*
* Join the specified IBSS/BSS network. The node is assumed to
* be passed in with a held reference.
@@ -763,6 +772,7 @@
/* XXX msg */
return 0;
}
+
/*
* Expand scan state into node's format.
* XXX may not need all this stuff
@@ -813,6 +823,29 @@
IEEE80211_F_DOSORT);
if (ieee80211_iserp_rateset(&ni->ni_rates))
ni->ni_flags |= IEEE80211_NODE_ERP;
+
+ /*
+ * Setup HT state for this node if it's available, otherwise
+ * non-STA modes won't pick this state up.
+ *
+ * For IBSS and related modes that don't go through an
+ * association request/response, the only appropriate place
+ * to setup the HT state is here.
+ */
+ if (ni->ni_ies.htinfo_ie != NULL &&
+ ni->ni_ies.htcap_ie != NULL &&
+ vap->iv_flags_ht & IEEE80211_FHT_HT) {
+ ieee80211_ht_node_init(ni);
+ ieee80211_ht_updateparams(ni,
+ ni->ni_ies.htcap_ie,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie,
+ IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+ ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie);
+ }
+ /* XXX else check for ath FF? */
+ /* XXX QoS? Difficult given that WME config is specific to a master */
+
ieee80211_node_setuptxparms(ni);
ieee80211_ratectl_node_init(ni);
@@ -930,6 +963,9 @@
case IEEE80211_ELEMID_HTCAP:
ies->htcap_ie = ie;
break;
+ case IEEE80211_ELEMID_HTINFO:
+ ies->htinfo_ie = ie;
+ break;
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_ELEMID_MESHID:
ies->meshid_ie = ie;
@@ -950,7 +986,6 @@
static void
node_cleanup(struct ieee80211_node *ni)
{
-#define N(a) (sizeof(a)/sizeof(a[0]))
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
int i;
@@ -1017,7 +1052,7 @@
*
* XXX does this leave us open to inheriting old state?
*/
- for (i = 0; i < N(ni->ni_rxfrag); i++)
+ for (i = 0; i < nitems(ni->ni_rxfrag); i++)
if (ni->ni_rxfrag[i] != NULL) {
m_freem(ni->ni_rxfrag[i]);
ni->ni_rxfrag[i] = NULL;
@@ -1026,7 +1061,6 @@
* Must be careful here to remove any key map entry w/o a LOR.
*/
ieee80211_node_delucastkey(ni);
-#undef N
}
static void
@@ -1396,7 +1430,7 @@
{
struct ieee80211_node *ni;
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC,
"%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
ni = ieee80211_dup_bss(vap, macaddr);
if (ni != NULL) {
@@ -1436,6 +1470,8 @@
const struct ieee80211_frame *wh,
const struct ieee80211_scanparams *sp)
{
+ int do_ht_setup = 0;
+
ni->ni_esslen = sp->ssid[1];
memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]);
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
@@ -1461,6 +1497,16 @@
if (ni->ni_ies.ath_ie != NULL)
ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
#endif
+ if (ni->ni_ies.htcap_ie != NULL)
+ ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
+ if (ni->ni_ies.htinfo_ie != NULL)
+ ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
+
+ if ((ni->ni_ies.htcap_ie != NULL) &&
+ (ni->ni_ies.htinfo_ie != NULL) &&
+ (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) {
+ do_ht_setup = 1;
+ }
}
/* NB: must be after ni_chan is setup */
@@ -1467,6 +1513,25 @@
ieee80211_setup_rates(ni, sp->rates, sp->xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
+
+ /*
+ * If the neighbor is HT compatible, flip that on.
+ */
+ if (do_ht_setup) {
+ IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
+ "%s: doing HT setup\n", __func__);
+ ieee80211_ht_node_init(ni);
+ ieee80211_ht_updateparams(ni,
+ ni->ni_ies.htcap_ie,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_setup_htrates(ni,
+ ni->ni_ies.htcap_ie,
+ IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+ ieee80211_setup_basic_htrates(ni,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_node_setuptxparms(ni);
+ ieee80211_ratectl_node_init(ni);
+ }
}
/*
@@ -1482,7 +1547,7 @@
{
struct ieee80211_node *ni;
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
"%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */
if (ni != NULL) {
@@ -2148,33 +2213,134 @@
ieee80211_node_timeout, ic);
}
-void
-ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
- ieee80211_iter_func *f, void *arg)
+/*
+ * Iterate over the node table and return an array of ref'ed nodes.
+ *
+ * This is separated out from calling the actual node function so that
+ * no LORs will occur.
+ *
+ * If there are too many nodes (ie, the number of nodes doesn't fit
+ * within 'max_aid' entries) then the node references will be freed
+ * and an error will be returned.
+ *
+ * The responsibility of allocating and freeing "ni_arr" is up to
+ * the caller.
+ */
+int
+ieee80211_iterate_nt(struct ieee80211_node_table *nt,
+ struct ieee80211_node **ni_arr, uint16_t max_aid)
{
+ u_int gen;
+ int i, j, ret;
struct ieee80211_node *ni;
- u_int gen;
IEEE80211_NODE_ITERATE_LOCK(nt);
+ IEEE80211_NODE_LOCK(nt);
+
gen = ++nt->nt_scangen;
-restart:
- IEEE80211_NODE_LOCK(nt);
+ i = ret = 0;
+
+ /*
+ * We simply assume here that since the node
+ * scan generation doesn't change (as
+ * we are holding both the node table and
+ * node table iteration locks), we can simply
+ * assign it to the node here.
+ */
TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- if (ni->ni_scangen != gen) {
- ni->ni_scangen = gen;
- (void) ieee80211_ref_node(ni);
- IEEE80211_NODE_UNLOCK(nt);
- (*f)(arg, ni);
- ieee80211_free_node(ni);
- goto restart;
+ if (i >= max_aid) {
+ ret = E2BIG;
+ if_printf(nt->nt_ic->ic_ifp,
+ "Node array overflow: max=%u", max_aid);
+ break;
}
+ ni_arr[i] = ieee80211_ref_node(ni);
+ ni_arr[i]->ni_scangen = gen;
+ i++;
}
+
+ /*
+ * It's safe to unlock here.
+ *
+ * If we're successful, the list is returned.
+ * If we're unsuccessful, the list is ignored
+ * and we remove our references.
+ *
+ * This avoids any potential LOR with
+ * ieee80211_free_node().
+ */
IEEE80211_NODE_UNLOCK(nt);
+ IEEE80211_NODE_ITERATE_UNLOCK(nt);
- IEEE80211_NODE_ITERATE_UNLOCK(nt);
+ /*
+ * If ret is non-zero, we hit some kind of error.
+ * Rather than walking some nodes, we'll walk none
+ * of them.
+ */
+ if (ret) {
+ for (j = 0; j < i; j++) {
+ /* ieee80211_free_node() locks by itself */
+ ieee80211_free_node(ni_arr[j]);
+ }
+ }
+
+ return (ret);
}
+/*
+ * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
+ * reference in the source.
+ *
+ * Note that this fetches 'max_aid' from the first VAP, rather than finding
+ * the largest max_aid from all VAPs.
+ */
void
+ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
+ ieee80211_iter_func *f, void *arg)
+{
+ struct ieee80211_node **ni_arr;
+ size_t size;
+ int i;
+ uint16_t max_aid;
+ struct ieee80211vap *vap;
+
+ /* Overdoing it default */
+ max_aid = IEEE80211_AID_MAX;
+
+ /* Handle the case of there being no vaps just yet */
+ vap = TAILQ_FIRST(&nt->nt_ic->ic_vaps);
+ if (vap != NULL)
+ max_aid = vap->iv_max_aid;
+
+ size = max_aid * sizeof(struct ieee80211_node *);
+ ni_arr = (struct ieee80211_node **) malloc(size, M_80211_NODE,
+ M_NOWAIT | M_ZERO);
+ if (ni_arr == NULL)
+ return;
+
+ /*
+ * If this fails, the node table won't have any
+ * valid entries - ieee80211_iterate_nt() frees
+ * the references to them. So don't try walking
+ * the table; just skip to the end and free the
+ * temporary memory.
+ */
+ if (ieee80211_iterate_nt(nt, ni_arr, max_aid) != 0)
+ goto done;
+
+ for (i = 0; i < max_aid; i++) {
+ if (ni_arr[i] == NULL) /* end of the list */
+ break;
+ (*f)(arg, ni_arr[i]);
+ /* ieee80211_free_node() locks by itself */
+ ieee80211_free_node(ni_arr[i]);
+ }
+
+done:
+ free(ni_arr, M_80211_NODE);
+}
+
+void
ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
{
printf("0x%p: mac %s refcnt %d\n", ni,
Modified: trunk/sys/net80211/ieee80211_node.h
===================================================================
--- trunk/sys/net80211/ieee80211_node.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_node.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_node.h 246497 2013-02-07 21:12:55Z monthadar $
*/
#ifndef _NET80211_IEEE80211_NODE_H_
#define _NET80211_IEEE80211_NODE_H_
@@ -204,6 +205,8 @@
struct callout ni_mltimer; /* link mesh timer */
uint8_t ni_mlrcnt; /* link mesh retry counter */
uint8_t ni_mltval; /* link mesh timer value */
+ struct callout ni_mlhtimer; /* link mesh backoff timer */
+ uint8_t ni_mlhcnt; /* link mesh holding counter */
/* 11n state */
uint16_t ni_htcap; /* HT capabilities */
@@ -214,7 +217,7 @@
uint8_t ni_htstbc; /* HT */
uint8_t ni_chw; /* negotiated channel width */
struct ieee80211_htrateset ni_htrates; /* negotiated ht rate set */
- struct ieee80211_tx_ampdu ni_tx_ampdu[WME_NUM_AC];
+ struct ieee80211_tx_ampdu ni_tx_ampdu[WME_NUM_TID];
struct ieee80211_rx_ampdu ni_rx_ampdu[WME_NUM_TID];
/* others */
@@ -299,8 +302,6 @@
*ni = NULL; /* guard against use */
}
-struct ieee80211com;
-
void ieee80211_node_attach(struct ieee80211com *);
void ieee80211_node_lateattach(struct ieee80211com *);
void ieee80211_node_detach(struct ieee80211com *);
@@ -326,6 +327,7 @@
void ieee80211_setupcurchan(struct ieee80211com *,
struct ieee80211_channel *);
void ieee80211_setcurchan(struct ieee80211com *, struct ieee80211_channel *);
+void ieee80211_update_chw(struct ieee80211com *);
int ieee80211_ibss_merge(struct ieee80211_node *);
struct ieee80211_scan_entry;
int ieee80211_sta_join(struct ieee80211vap *, struct ieee80211_channel *,
@@ -439,6 +441,8 @@
void ieee80211_node_timeout(void *arg);
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
+int ieee80211_iterate_nt(struct ieee80211_node_table *,
+ struct ieee80211_node **, uint16_t);
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
ieee80211_iter_func *, void *);
Modified: trunk/sys/net80211/ieee80211_output.c
===================================================================
--- trunk/sys/net80211/ieee80211_output.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_output.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_output.c 283855 2015-05-31 23:29:04Z ae $");
#include "opt_inet.h"
#include "opt_inet6.h"
@@ -110,31 +111,321 @@
#endif
/*
- * Start method for vap's. All packets from the stack come
- * through here. We handle common processing of the packets
- * before dispatching them to the underlying device.
+ * Transmit a frame to the given destination on the given VAP.
+ *
+ * It's up to the caller to figure out the details of who this
+ * is going to and resolving the node.
+ *
+ * This routine takes care of queuing it for power save,
+ * A-MPDU state stuff, fast-frames state stuff, encapsulation
+ * if required, then passing it up to the driver layer.
+ *
+ * This routine (for now) consumes the mbuf and frees the node
+ * reference; it ideally will return a TX status which reflects
+ * whether the mbuf was consumed or not, so the caller can
+ * free the mbuf (if appropriate) and the node reference (again,
+ * if appropriate.)
*/
-void
-ieee80211_start(struct ifnet *ifp)
+int
+ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
+ struct ieee80211_node *ni)
{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *ifp = vap->iv_ifp;
+ int error, len, mcast;
+
+ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
+ (m->m_flags & M_PWR_SAV) == 0) {
+ /*
+ * Station in power save mode; pass the frame
+ * to the 802.11 layer and continue. We'll get
+ * the frame back when the time is right.
+ * XXX lose WDS vap linkage?
+ */
+ if (ieee80211_pwrsave(ni, m) != 0)
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ ieee80211_free_node(ni);
+
+ /*
+ * We queued it fine, so tell the upper layer
+ * that we consumed it.
+ */
+ return (0);
+ }
+ /* calculate priority so drivers can find the tx queue */
+ if (ieee80211_classify(ni, m)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
+ ni->ni_macaddr, NULL,
+ "%s", "classification failure");
+ vap->iv_stats.is_tx_classify++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ ieee80211_free_node(ni);
+
+ /* XXX better status? */
+ return (0);
+ }
+ /*
+ * Stash the node pointer. Note that we do this after
+ * any call to ieee80211_dwds_mcast because that code
+ * uses any existing value for rcvif to identify the
+ * interface it (might have been) received on.
+ */
+ m->m_pkthdr.rcvif = (void *)ni;
+ mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0;
+ len = m->m_pkthdr.len;
+
+ BPF_MTAP(ifp, m); /* 802.3 tx */
+
+ /*
+ * Check if A-MPDU tx aggregation is setup or if we
+ * should try to enable it. The sta must be associated
+ * with HT and A-MPDU enabled for use. When the policy
+ * routine decides we should enable A-MPDU we issue an
+ * ADDBA request and wait for a reply. The frame being
+ * encapsulated will go out w/o using A-MPDU, or possibly
+ * it might be collected by the driver and held/retransmit.
+ * The default ic_ampdu_enable routine handles staggering
+ * ADDBA requests in case the receiver NAK's us or we are
+ * otherwise unable to establish a BA stream.
+ */
+ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
+ (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) &&
+ (m->m_flags & M_EAPOL) == 0) {
+ int tid = WME_AC_TO_TID(M_WME_GETAC(m));
+ struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid];
+
+ ieee80211_txampdu_count_packet(tap);
+ if (IEEE80211_AMPDU_RUNNING(tap)) {
+ /*
+ * Operational, mark frame for aggregation.
+ *
+ * XXX do tx aggregation here
+ */
+ m->m_flags |= M_AMPDU_MPDU;
+ } else if (!IEEE80211_AMPDU_REQUESTED(tap) &&
+ ic->ic_ampdu_enable(ni, tap)) {
+ /*
+ * Not negotiated yet, request service.
+ */
+ ieee80211_ampdu_request(ni, tap);
+ /* XXX hold frame for reply? */
+ }
+ }
+
+#ifdef IEEE80211_SUPPORT_SUPERG
+ else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) {
+ m = ieee80211_ff_check(ni, m);
+ if (m == NULL) {
+ /* NB: any ni ref held on stageq */
+ return (0);
+ }
+ }
+#endif /* IEEE80211_SUPPORT_SUPERG */
+
+ /*
+ * Grab the TX lock - serialise the TX process from this
+ * point (where TX state is being checked/modified)
+ * through to driver queue.
+ */
+ IEEE80211_TX_LOCK(ic);
+
+ if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(vap, ni, m);
+ if (m == NULL) {
+ /* NB: stat+msg handled in ieee80211_encap */
+ IEEE80211_TX_UNLOCK(ic);
+ ieee80211_free_node(ni);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ return (ENOBUFS);
+ }
+ }
+ error = ieee80211_parent_xmitpkt(ic, m);
+
+ /*
+ * Unlock at this point - no need to hold it across
+ * ieee80211_free_node() (ie, the comlock)
+ */
+ IEEE80211_TX_UNLOCK(ic);
+ if (error != 0) {
+ /* NB: IFQ_HANDOFF reclaims mbuf */
+ ieee80211_free_node(ni);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ } else {
+ ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast);
+ if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
+ }
+ ic->ic_lastdata = ticks;
+
+ return (0);
+}
+
+
+
+/*
+ * Send the given mbuf through the given vap.
+ *
+ * This consumes the mbuf regardless of whether the transmit
+ * was successful or not.
+ *
+ * This does none of the initial checks that ieee80211_start()
+ * does (eg CAC timeout, interface wakeup) - the caller must
+ * do this first.
+ */
+static int
+ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
+{
#define IS_DWDS(vap) \
(vap->iv_opmode == IEEE80211_M_WDS && \
(vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
- struct ieee80211vap *vap = ifp->if_softc;
struct ieee80211com *ic = vap->iv_ic;
- struct ifnet *parent = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ifp;
struct ieee80211_node *ni;
- struct mbuf *m;
struct ether_header *eh;
- int error;
+ /*
+ * Cancel any background scan.
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_anyscan(vap);
+ /*
+ * Find the node for the destination so we can do
+ * things like power save and fast frames aggregation.
+ *
+ * NB: past this point various code assumes the first
+ * mbuf has the 802.3 header present (and contiguous).
+ */
+ ni = NULL;
+ if (m->m_len < sizeof(struct ether_header) &&
+ (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+ "discard frame, %s\n", "m_pullup failed");
+ vap->iv_stats.is_tx_nobuf++; /* XXX */
+ ifp->if_oerrors++;
+ return (ENOBUFS);
+ }
+ eh = mtod(m, struct ether_header *);
+ if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+ if (IS_DWDS(vap)) {
+ /*
+ * Only unicast frames from the above go out
+ * DWDS vaps; multicast frames are handled by
+ * dispatching the frame as it comes through
+ * the AP vap (see below).
+ */
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
+ eh->ether_dhost, "mcast", "%s", "on DWDS");
+ vap->iv_stats.is_dwds_mcast++;
+ m_freem(m);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ /*
+ * Spam DWDS vap's w/ multicast traffic.
+ */
+ /* XXX only if dwds in use? */
+ ieee80211_dwds_mcast(vap, m);
+ }
+ }
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode != IEEE80211_M_MBSS) {
+#endif
+ ni = ieee80211_find_txnode(vap, eh->ether_dhost);
+ if (ni == NULL) {
+ /* NB: ieee80211_find_txnode does stat+msg */
+ ifp->if_oerrors++;
+ m_freem(m);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ if (ni->ni_associd == 0 &&
+ (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
+ eh->ether_dhost, NULL,
+ "sta not associated (type 0x%04x)",
+ htons(eh->ether_type));
+ vap->iv_stats.is_tx_notassoc++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ ieee80211_free_node(ni);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+#ifdef IEEE80211_SUPPORT_MESH
+ } else {
+ if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
+ /*
+ * Proxy station only if configured.
+ */
+ if (!ieee80211_mesh_isproxyena(vap)) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_OUTPUT |
+ IEEE80211_MSG_MESH,
+ eh->ether_dhost, NULL,
+ "%s", "proxy not enabled");
+ vap->iv_stats.is_mesh_notproxy++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+ "forward frame from DS SA(%6D), DA(%6D)\n",
+ eh->ether_shost, ":",
+ eh->ether_dhost, ":");
+ ieee80211_mesh_proxy_check(vap, eh->ether_shost);
+ }
+ ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
+ if (ni == NULL) {
+ /*
+ * NB: ieee80211_mesh_discover holds/disposes
+ * frame (e.g. queueing on path discovery).
+ */
+ ifp->if_oerrors++;
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ }
+#endif
+
+ /*
+ * We've resolved the sender, so attempt to transmit it.
+ */
+ if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0)
+ return (ENOBUFS);
+ return (0);
+#undef IS_DWDS
+}
+
+/*
+ * Start method for vap's. All packets from the stack come
+ * through here. We handle common processing of the packets
+ * before dispatching them to the underlying device.
+ *
+ * if_transmit() requires that the mbuf be consumed by this call
+ * regardless of the return condition.
+ */
+int
+ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m)
+{
+ struct ieee80211vap *vap = ifp->if_softc;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *parent = ic->ic_ifp;
+
/* NB: parent must be up and running */
if (!IFNET_IS_UP_RUNNING(parent)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
"%s: ignore queue, parent %s not up+running\n",
__func__, parent->if_xname);
- /* XXX stat */
- return;
+ m_freem(m);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ return (ENETDOWN);
}
if (vap->iv_state == IEEE80211_S_SLEEP) {
/*
@@ -141,7 +432,8 @@
* In power save, wakeup device for transmit.
*/
ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
- return;
+ m_freem(m);
+ return (0);
}
/*
* No data frames go out unless we're running.
@@ -157,237 +449,74 @@
"%s: ignore queue, in %s state\n",
__func__, ieee80211_state_name[vap->iv_state]);
vap->iv_stats.is_tx_badstate++;
+ IEEE80211_UNLOCK(ic);
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- IEEE80211_UNLOCK(ic);
- return;
+ m_freem(m);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ return (ENETDOWN);
}
IEEE80211_UNLOCK(ic);
}
- for (;;) {
- IFQ_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
- break;
- /*
- * Sanitize mbuf flags for net80211 use. We cannot
- * clear M_PWR_SAV or M_MORE_DATA because these may
- * be set for frames that are re-submitted from the
- * power save queue.
- *
- * NB: This must be done before ieee80211_classify as
- * it marks EAPOL in frames with M_EAPOL.
- */
- m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
- /*
- * Cancel any background scan.
- */
- if (ic->ic_flags & IEEE80211_F_SCAN)
- ieee80211_cancel_anyscan(vap);
- /*
- * Find the node for the destination so we can do
- * things like power save and fast frames aggregation.
- *
- * NB: past this point various code assumes the first
- * mbuf has the 802.3 header present (and contiguous).
- */
- ni = NULL;
- if (m->m_len < sizeof(struct ether_header) &&
- (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
- "discard frame, %s\n", "m_pullup failed");
- vap->iv_stats.is_tx_nobuf++; /* XXX */
- ifp->if_oerrors++;
- continue;
- }
- eh = mtod(m, struct ether_header *);
- if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
- if (IS_DWDS(vap)) {
- /*
- * Only unicast frames from the above go out
- * DWDS vaps; multicast frames are handled by
- * dispatching the frame as it comes through
- * the AP vap (see below).
- */
- IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
- eh->ether_dhost, "mcast", "%s", "on DWDS");
- vap->iv_stats.is_dwds_mcast++;
- m_freem(m);
- continue;
- }
- if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
- /*
- * Spam DWDS vap's w/ multicast traffic.
- */
- /* XXX only if dwds in use? */
- ieee80211_dwds_mcast(vap, m);
- }
- }
-#ifdef IEEE80211_SUPPORT_MESH
- if (vap->iv_opmode != IEEE80211_M_MBSS) {
-#endif
- ni = ieee80211_find_txnode(vap, eh->ether_dhost);
- if (ni == NULL) {
- /* NB: ieee80211_find_txnode does stat+msg */
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
- if (ni->ni_associd == 0 &&
- (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
- IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
- eh->ether_dhost, NULL,
- "sta not associated (type 0x%04x)",
- htons(eh->ether_type));
- vap->iv_stats.is_tx_notassoc++;
- ifp->if_oerrors++;
- m_freem(m);
- ieee80211_free_node(ni);
- continue;
- }
-#ifdef IEEE80211_SUPPORT_MESH
- } else {
- if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
- /*
- * Proxy station only if configured.
- */
- if (!ieee80211_mesh_isproxyena(vap)) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_OUTPUT |
- IEEE80211_MSG_MESH,
- eh->ether_dhost, NULL,
- "%s", "proxy not enabled");
- vap->iv_stats.is_mesh_notproxy++;
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
- ieee80211_mesh_proxy_check(vap, eh->ether_shost);
- }
- ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
- if (ni == NULL) {
- /*
- * NB: ieee80211_mesh_discover holds/disposes
- * frame (e.g. queueing on path discovery).
- */
- ifp->if_oerrors++;
- continue;
- }
- }
-#endif
- if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
- (m->m_flags & M_PWR_SAV) == 0) {
- /*
- * Station in power save mode; pass the frame
- * to the 802.11 layer and continue. We'll get
- * the frame back when the time is right.
- * XXX lose WDS vap linkage?
- */
- (void) ieee80211_pwrsave(ni, m);
- ieee80211_free_node(ni);
- continue;
- }
- /* calculate priority so drivers can find the tx queue */
- if (ieee80211_classify(ni, m)) {
- IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
- eh->ether_dhost, NULL,
- "%s", "classification failure");
- vap->iv_stats.is_tx_classify++;
- ifp->if_oerrors++;
- m_freem(m);
- ieee80211_free_node(ni);
- continue;
- }
- /*
- * Stash the node pointer. Note that we do this after
- * any call to ieee80211_dwds_mcast because that code
- * uses any existing value for rcvif to identify the
- * interface it (might have been) received on.
- */
- m->m_pkthdr.rcvif = (void *)ni;
- BPF_MTAP(ifp, m); /* 802.3 tx */
-
- /*
- * Check if A-MPDU tx aggregation is setup or if we
- * should try to enable it. The sta must be associated
- * with HT and A-MPDU enabled for use. When the policy
- * routine decides we should enable A-MPDU we issue an
- * ADDBA request and wait for a reply. The frame being
- * encapsulated will go out w/o using A-MPDU, or possibly
- * it might be collected by the driver and held/retransmit.
- * The default ic_ampdu_enable routine handles staggering
- * ADDBA requests in case the receiver NAK's us or we are
- * otherwise unable to establish a BA stream.
- */
- if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
- (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) &&
- (m->m_flags & M_EAPOL) == 0) {
- const int ac = M_WME_GETAC(m);
- struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
+ /*
+ * Sanitize mbuf flags for net80211 use. We cannot
+ * clear M_PWR_SAV or M_MORE_DATA because these may
+ * be set for frames that are re-submitted from the
+ * power save queue.
+ *
+ * NB: This must be done before ieee80211_classify as
+ * it marks EAPOL in frames with M_EAPOL.
+ */
+ m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
- ieee80211_txampdu_count_packet(tap);
- if (IEEE80211_AMPDU_RUNNING(tap)) {
- /*
- * Operational, mark frame for aggregation.
- *
- * XXX do tx aggregation here
- */
- m->m_flags |= M_AMPDU_MPDU;
- } else if (!IEEE80211_AMPDU_REQUESTED(tap) &&
- ic->ic_ampdu_enable(ni, tap)) {
- /*
- * Not negotiated yet, request service.
- */
- ieee80211_ampdu_request(ni, tap);
- /* XXX hold frame for reply? */
- }
- }
-#ifdef IEEE80211_SUPPORT_SUPERG
- else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) {
- m = ieee80211_ff_check(ni, m);
- if (m == NULL) {
- /* NB: any ni ref held on stageq */
- continue;
- }
- }
-#endif /* IEEE80211_SUPPORT_SUPERG */
- if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
- /*
- * Encapsulate the packet in prep for transmission.
- */
- m = ieee80211_encap(vap, ni, m);
- if (m == NULL) {
- /* NB: stat+msg handled in ieee80211_encap */
- ieee80211_free_node(ni);
- continue;
- }
- }
+ /*
+ * Bump to the packet transmission path.
+ * The mbuf will be consumed here.
+ */
+ return (ieee80211_start_pkt(vap, m));
+}
- error = parent->if_transmit(parent, m);
- if (error != 0) {
- /* NB: IFQ_HANDOFF reclaims mbuf */
- ieee80211_free_node(ni);
- } else {
- ifp->if_opackets++;
- }
- ic->ic_lastdata = ticks;
- }
-#undef IS_DWDS
+void
+ieee80211_vap_qflush(struct ifnet *ifp)
+{
+
+ /* Empty for now */
}
/*
+ * 802.11 raw output routine.
+ */
+int
+ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni,
+ struct mbuf *m, const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ return (ic->ic_raw_xmit(ni, m, params));
+}
+
+/*
* 802.11 output routine. This is (currently) used only to
* connect bpf write calls to the 802.11 layer for injecting
* raw 802.11 frames.
*/
+#if __FreeBSD_version >= 1000031
int
ieee80211_output(struct ifnet *ifp, struct mbuf *m,
+ const struct sockaddr *dst, struct route *ro)
+#else
+int
+ieee80211_output(struct ifnet *ifp, struct mbuf *m,
struct sockaddr *dst, struct route *ro)
+#endif
{
#define senderr(e) do { error = (e); goto bad;} while (0)
struct ieee80211_node *ni = NULL;
struct ieee80211vap *vap;
struct ieee80211_frame *wh;
+ struct ieee80211com *ic = NULL;
int error;
+ int ret;
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
/*
@@ -401,6 +530,7 @@
senderr(ENETDOWN);
}
vap = ifp->if_softc;
+ ic = vap->iv_ic;
/*
* Hand to the 802.3 code if not tagged as
* a raw 802.11 frame.
@@ -481,6 +611,8 @@
/* NB: ieee80211_encap does not include 802.11 header */
IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len);
+ IEEE80211_TX_LOCK(ic);
+
/*
* NB: DLT_IEEE802_11_RADIO identifies the parameters are
* present by setting the sa_len field of the sockaddr (yes,
@@ -487,9 +619,11 @@
* this is a hack).
* NB: we assume sa_data is suitably aligned to cast.
*/
- return vap->iv_ic->ic_raw_xmit(ni, m,
+ ret = ieee80211_raw_output(vap, ni, m,
(const struct ieee80211_bpf_params *)(dst->sa_len ?
dst->sa_data : NULL));
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
bad:
if (m != NULL)
m_freem(m);
@@ -520,6 +654,8 @@
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
ieee80211_seq seqno;
+ IEEE80211_TX_LOCK_ASSERT(ni->ni_ic);
+
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
switch (vap->iv_opmode) {
@@ -551,7 +687,6 @@
break;
case IEEE80211_M_MBSS:
#ifdef IEEE80211_SUPPORT_MESH
- /* XXX add support for proxied addresses */
if (IEEE80211_IS_MULTICAST(da)) {
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
/* XXX next hop */
@@ -584,7 +719,7 @@
}
*(uint16_t *)&wh->i_dur[0] = 0;
- tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)];
+ tap = &ni->ni_tx_ampdu[tid];
if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap))
m->m_flags |= M_AMPDU_MPDU;
else {
@@ -614,6 +749,7 @@
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
+ int ret;
KASSERT(ni != NULL, ("null node"));
@@ -629,12 +765,14 @@
return EIO; /* XXX */
}
- M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
if (m == NULL) {
ieee80211_free_node(ni);
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
+
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID,
@@ -642,7 +780,7 @@
if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1,
"encrypting frame (%s)", __func__);
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
+ wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
}
m->m_flags |= M_ENCAP; /* mark encapsulated */
@@ -663,7 +801,9 @@
#endif
IEEE80211_NODE_STAT(ni, tx_mgmt);
- return ic->ic_raw_xmit(ni, m, params);
+ ret = ieee80211_raw_output(vap, ni, m, params);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -687,6 +827,7 @@
struct ieee80211_frame *wh;
int hdrlen;
uint8_t *frm;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
@@ -715,7 +856,7 @@
}
KASSERT(M_LEADINGSPACE(m) >= hdrlen,
("leading space %zd", M_LEADINGSPACE(m)));
- M_PREPEND(m, hdrlen, M_DONTWAIT);
+ M_PREPEND(m, hdrlen, M_NOWAIT);
if (m == NULL) {
/* NB: cannot happen */
ieee80211_free_node(ni);
@@ -722,6 +863,8 @@
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
+
wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */
if (ni->ni_flags & IEEE80211_NODE_QOS) {
const int tid = WME_AC_TO_TID(WME_AC_BE);
@@ -764,7 +907,9 @@
ieee80211_chan2ieee(ic, ic->ic_curchan),
wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
- return ic->ic_raw_xmit(ni, m, NULL);
+ ret = ieee80211_raw_output(vap, ni, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -932,7 +1077,7 @@
return NULL;
}
KASSERT(needed_space <= MHLEN,
- ("not enough room, need %u got %zu\n", needed_space, MHLEN));
+ ("not enough room, need %u got %d\n", needed_space, MHLEN));
/*
* Setup new mbuf to have leading space to prepend the
* 802.11 header and any crypto header bits that are
@@ -1011,10 +1156,13 @@
struct mbuf *m)
{
#define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh))
+#define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc)
struct ieee80211com *ic = ni->ni_ic;
#ifdef IEEE80211_SUPPORT_MESH
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_meshcntl_ae10 *mc;
+ struct ieee80211_mesh_route *rt = NULL;
+ int dir = -1;
#endif
struct ether_header eh;
struct ieee80211_frame *wh;
@@ -1024,6 +1172,8 @@
ieee80211_seq seqno;
int meshhdrsize, meshae;
uint8_t *qos;
+
+ IEEE80211_TX_LOCK_ASSERT(ic);
/*
* Copy existing Ethernet header to a safe place. The
@@ -1069,9 +1219,11 @@
* ap's require all data frames to be QoS-encapsulated
* once negotiated in which case we'll need to make this
* configurable.
+ * NB: mesh data frames are QoS.
*/
- addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) &&
- (m->m_flags & M_EAPOL) == 0;
+ addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) ||
+ (vap->iv_opmode == IEEE80211_M_MBSS)) &&
+ (m->m_flags & M_EAPOL) == 0;
if (addqos)
hdrsize = sizeof(struct ieee80211_qosframe);
else
@@ -1093,21 +1245,40 @@
* w/ 4-address format and address extension mode 10
*/
is4addr = 0; /* NB: don't use, disable */
- if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
- hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */
- meshhdrsize = sizeof(struct ieee80211_meshcntl);
- /* XXX defines for AE modes */
- if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
- if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
- meshae = 0;
- else
- meshae = 4; /* NB: pseudo */
- } else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
- meshae = 1;
- meshhdrsize += 1*IEEE80211_ADDR_LEN;
+ if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
+ rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost);
+ KASSERT(rt != NULL, ("route is NULL"));
+ dir = IEEE80211_FC1_DIR_DSTODS;
+ hdrsize += IEEE80211_ADDR_LEN;
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate,
+ vap->iv_myaddr)) {
+ IEEE80211_NOTE_MAC(vap,
+ IEEE80211_MSG_MESH,
+ eh.ether_dhost,
+ "%s", "trying to send to ourself");
+ goto bad;
+ }
+ meshae = IEEE80211_MESH_AE_10;
+ meshhdrsize =
+ sizeof(struct ieee80211_meshcntl_ae10);
+ } else {
+ meshae = IEEE80211_MESH_AE_00;
+ meshhdrsize =
+ sizeof(struct ieee80211_meshcntl);
+ }
} else {
- meshae = 2;
- meshhdrsize += 2*IEEE80211_ADDR_LEN;
+ dir = IEEE80211_FC1_DIR_FROMDS;
+ if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
+ /* proxy group */
+ meshae = IEEE80211_MESH_AE_01;
+ meshhdrsize =
+ sizeof(struct ieee80211_meshcntl_ae01);
+ } else {
+ /* group */
+ meshae = IEEE80211_MESH_AE_00;
+ meshhdrsize = sizeof(struct ieee80211_meshcntl);
+ }
}
} else {
#endif
@@ -1164,7 +1335,7 @@
}
datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */
- M_PREPEND(m, hdrspace + meshhdrsize, M_DONTWAIT);
+ M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT);
if (m == NULL) {
vap->iv_stats.is_tx_nobuf++;
goto bad;
@@ -1208,44 +1379,52 @@
/* NB: offset by hdrspace to deal with DATAPAD */
mc = (struct ieee80211_meshcntl_ae10 *)
(mtod(m, uint8_t *) + hdrspace);
+ wh->i_fc[1] = dir;
switch (meshae) {
- case 0: /* ucast, no proxy */
- wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
- IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
- IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
- IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
- IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
+ case IEEE80211_MESH_AE_00: /* no proxy */
mc->mc_flags = 0;
- qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
+ if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */
+ IEEE80211_ADDR_COPY(wh->i_addr1,
+ ni->ni_macaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr2,
+ vap->iv_myaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr3,
+ eh.ether_dhost);
+ IEEE80211_ADDR_COPY(WH4(wh)->i_addr4,
+ eh.ether_shost);
+ qos =((struct ieee80211_qosframe_addr4 *)
+ wh)->i_qos;
+ } else if (dir == IEEE80211_FC1_DIR_FROMDS) {
+ /* mcast */
+ IEEE80211_ADDR_COPY(wh->i_addr1,
+ eh.ether_dhost);
+ IEEE80211_ADDR_COPY(wh->i_addr2,
+ vap->iv_myaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr3,
+ eh.ether_shost);
+ qos = ((struct ieee80211_qosframe *)
+ wh)->i_qos;
+ }
break;
- case 4: /* mcast, no proxy */
+ case IEEE80211_MESH_AE_01: /* mcast, proxy */
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
- IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
- mc->mc_flags = 0; /* NB: AE is really 0 */
- qos = ((struct ieee80211_qosframe *) wh)->i_qos;
- break;
- case 1: /* mcast, proxy */
- wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
- IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
- IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
mc->mc_flags = 1;
- IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost);
+ IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4,
+ eh.ether_shost);
qos = ((struct ieee80211_qosframe *) wh)->i_qos;
break;
- case 2: /* ucast, proxy */
- wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
- IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
+ case IEEE80211_MESH_AE_10: /* ucast, proxy */
+ KASSERT(rt != NULL, ("route is NULL"));
+ IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop);
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
- /* XXX not right, need MeshDA */
- IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
- /* XXX assume are MeshSA */
+ IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate);
IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
- mc->mc_flags = 2;
- IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost);
- IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost);
+ mc->mc_flags = IEEE80211_MESH_AE_10;
+ IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost);
+ IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
break;
default:
@@ -1277,7 +1456,12 @@
qos[0] = tid & IEEE80211_QOS_TID;
if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
- qos[1] = 0;
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode == IEEE80211_M_MBSS)
+ qos[1] = IEEE80211_QOS_MC;
+ else
+#endif
+ qos[1] = 0;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
if ((m->m_flags & M_AMPDU_MPDU) == 0) {
@@ -1321,7 +1505,7 @@
(vap->iv_opmode == IEEE80211_M_STA ?
!IEEE80211_KEY_UNDEFINED(key) :
!IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) {
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
+ wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT,
eh.ether_dhost,
@@ -1351,6 +1535,7 @@
m_freem(m);
return NULL;
#undef WH4
+#undef MC01
}
/*
@@ -1365,18 +1550,28 @@
ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
u_int hdrsize, u_int ciphdrsize, u_int mtu)
{
+ struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_frame *wh, *whf;
struct mbuf *m, *prev, *next;
u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
+ u_int hdrspace;
KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
KASSERT(m0->m_pkthdr.len > mtu,
("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
+ /*
+ * Honor driver DATAPAD requirement.
+ */
+ if (ic->ic_flags & IEEE80211_F_DATAPAD)
+ hdrspace = roundup(hdrsize, sizeof(uint32_t));
+ else
+ hdrspace = hdrsize;
+
wh = mtod(m0, struct ieee80211_frame *);
/* NB: mark the first frag; it will be propagated below */
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
- totalhdrsize = hdrsize + ciphdrsize;
+ totalhdrsize = hdrspace + ciphdrsize;
fragno = 1;
off = mtu - ciphdrsize;
remainder = m0->m_pkthdr.len - off;
@@ -1389,9 +1584,9 @@
KASSERT(fragsize < MCLBYTES,
("fragment size %u too big!", fragsize));
if (fragsize > MHLEN)
- m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
else
- m = m_gethdr(M_DONTWAIT, MT_DATA);
+ m = m_gethdr(M_NOWAIT, MT_DATA);
if (m == NULL)
goto bad;
/* leave room to prepend any cipher header */
@@ -1402,9 +1597,20 @@
* we mark the first fragment with the MORE_FRAG bit
* it automatically is propagated to each fragment; we
* need only clear it on the last fragment (done below).
+ * NB: frag 1+ dont have Mesh Control field present.
*/
whf = mtod(m, struct ieee80211_frame *);
memcpy(whf, wh, hdrsize);
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode == IEEE80211_M_MBSS) {
+ if (IEEE80211_IS_DSTODS(wh))
+ ((struct ieee80211_qosframe_addr4 *)
+ whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
+ else
+ ((struct ieee80211_qosframe *)
+ whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
+ }
+#endif
*(uint16_t *)&whf->i_seq[0] |= htole16(
(fragno & IEEE80211_SEQ_FRAG_MASK) <<
IEEE80211_SEQ_FRAG_SHIFT);
@@ -1412,9 +1618,10 @@
payload = fragsize - totalhdrsize;
/* NB: destination is known to be contiguous */
- m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize);
- m->m_len = hdrsize + payload;
- m->m_pkthdr.len = hdrsize + payload;
+
+ m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace);
+ m->m_len = hdrspace + payload;
+ m->m_pkthdr.len = hdrspace + payload;
m->m_flags |= M_FRAG;
/* chain up the fragment */
@@ -1661,6 +1868,33 @@
}
/*
+ * Add an 11h Quiet time element to a frame.
+ */
+static uint8_t *
+ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap)
+{
+ struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm;
+
+ quiet->quiet_ie = IEEE80211_ELEMID_QUIET;
+ quiet->len = 6;
+ if (vap->iv_quiet_count_value == 1)
+ vap->iv_quiet_count_value = vap->iv_quiet_count;
+ else if (vap->iv_quiet_count_value > 1)
+ vap->iv_quiet_count_value--;
+
+ if (vap->iv_quiet_count_value == 0) {
+ /* value 0 is reserved as per 802.11h standerd */
+ vap->iv_quiet_count_value = 1;
+ }
+
+ quiet->tbttcount = vap->iv_quiet_count_value;
+ quiet->period = vap->iv_quiet_period;
+ quiet->duration = htole16(vap->iv_quiet_duration);
+ quiet->offset = htole16(vap->iv_quiet_offset);
+ return frm + sizeof(*quiet);
+}
+
+/*
* Add an 11h Channel Switch Announcement element to a frame.
* Note that we use the per-vap CSA count to adjust the global
* counter so we can use this routine to form probe response
@@ -1704,6 +1938,40 @@
return add_appie(frm, ic->ic_countryie);
}
+uint8_t *
+ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap)
+{
+ if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL)
+ return (add_ie(frm, vap->iv_wpa_ie));
+ else {
+ /* XXX else complain? */
+ return (frm);
+ }
+}
+
+uint8_t *
+ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap)
+{
+ if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL)
+ return (add_ie(frm, vap->iv_rsn_ie));
+ else {
+ /* XXX else complain? */
+ return (frm);
+ }
+}
+
+uint8_t *
+ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni)
+{
+ if (ni->ni_flags & IEEE80211_NODE_QOS) {
+ *frm++ = IEEE80211_ELEMID_QOS;
+ *frm++ = 1;
+ *frm++ = 0;
+ }
+
+ return (frm);
+}
+
/*
* Send a probe request frame with the specified ssid
* and any optional information element data.
@@ -1723,6 +1991,7 @@
const struct ieee80211_rateset *rs;
struct mbuf *m;
uint8_t *frm;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
@@ -1771,17 +2040,9 @@
frm = ieee80211_add_ssid(frm, ssid, ssidlen);
rs = ieee80211_get_suprates(ic, ic->ic_curchan);
frm = ieee80211_add_rates(frm, rs);
- if (vap->iv_flags & IEEE80211_F_WPA2) {
- if (vap->iv_rsn_ie != NULL)
- frm = add_ie(frm, vap->iv_rsn_ie);
- /* XXX else complain? */
- }
+ frm = ieee80211_add_rsn(frm, vap);
frm = ieee80211_add_xrates(frm, rs);
- if (vap->iv_flags & IEEE80211_F_WPA1) {
- if (vap->iv_wpa_ie != NULL)
- frm = add_ie(frm, vap->iv_wpa_ie);
- /* XXX else complain? */
- }
+ frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_appie_probereq != NULL)
frm = add_appie(frm, vap->iv_appie_probereq);
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
@@ -1788,7 +2049,7 @@
KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame),
("leading space %zd", M_LEADINGSPACE(m)));
- M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
if (m == NULL) {
/* NB: cannot happen */
ieee80211_free_node(ni);
@@ -1795,6 +2056,7 @@
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
@@ -1822,7 +2084,9 @@
} else
params.ibp_try0 = tp->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ ret = ieee80211_raw_output(vap, ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -2044,11 +2308,7 @@
frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
frm = ieee80211_add_rates(frm, &ni->ni_rates);
- if (vap->iv_flags & IEEE80211_F_WPA2) {
- if (vap->iv_rsn_ie != NULL)
- frm = add_ie(frm, vap->iv_rsn_ie);
- /* XXX else complain? */
- }
+ frm = ieee80211_add_rsn(frm, vap);
frm = ieee80211_add_xrates(frm, &ni->ni_rates);
if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) {
frm = ieee80211_add_powercapability(frm,
@@ -2059,11 +2319,7 @@
ni->ni_ies.htcap_ie != NULL &&
ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP)
frm = ieee80211_add_htcap(frm, ni);
- if (vap->iv_flags & IEEE80211_F_WPA1) {
- if (vap->iv_wpa_ie != NULL)
- frm = add_ie(frm, vap->iv_wpa_ie);
- /* XXX else complain */
- }
+ frm = ieee80211_add_wpa(frm, vap);
if ((ic->ic_flags & IEEE80211_F_WME) &&
ni->ni_ies.wme_ie != NULL)
frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
@@ -2253,6 +2509,7 @@
+ IEEE80211_COUNTRY_MAX_SIZE
+ 3
+ sizeof(struct ieee80211_csa_ie)
+ + sizeof(struct ieee80211_quiet_ie)
+ 3
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ sizeof(struct ieee80211_ie_wpa)
@@ -2319,14 +2576,17 @@
if (ic->ic_flags & IEEE80211_F_CSAPENDING)
frm = ieee80211_add_csa(frm, vap);
}
+ if (vap->iv_flags & IEEE80211_F_DOTH) {
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
+ if (vap->iv_quiet)
+ frm = ieee80211_add_quiet(frm, vap);
+ }
+ }
if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
frm = ieee80211_add_erp(frm, ic);
frm = ieee80211_add_xrates(frm, rs);
- if (vap->iv_flags & IEEE80211_F_WPA2) {
- if (vap->iv_rsn_ie != NULL)
- frm = add_ie(frm, vap->iv_rsn_ie);
- /* XXX else complain? */
- }
+ frm = ieee80211_add_rsn(frm, vap);
/*
* NB: legacy 11b clients do not get certain ie's.
* The caller identifies such clients by passing
@@ -2338,11 +2598,7 @@
frm = ieee80211_add_htcap(frm, bss);
frm = ieee80211_add_htinfo(frm, bss);
}
- if (vap->iv_flags & IEEE80211_F_WPA1) {
- if (vap->iv_wpa_ie != NULL)
- frm = add_ie(frm, vap->iv_wpa_ie);
- /* XXX else complain? */
- }
+ frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME)
frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
@@ -2383,6 +2639,7 @@
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_frame *wh;
struct mbuf *m;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss,
@@ -2408,9 +2665,10 @@
return ENOMEM;
}
- M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
KASSERT(m != NULL, ("no room for header"));
+ IEEE80211_TX_LOCK(ic);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(bss, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
@@ -2426,7 +2684,9 @@
legacy ? " <legacy>" : "");
IEEE80211_NODE_STAT(bss, tx_mgmt);
- return ic->ic_raw_xmit(bss, m, NULL);
+ ret = ieee80211_raw_output(vap, bss, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -2442,7 +2702,7 @@
struct mbuf *m;
/* XXX honor ic_headroom */
- m = m_gethdr(M_DONTWAIT, MT_DATA);
+ m = m_gethdr(M_NOWAIT, MT_DATA);
if (m != NULL) {
rts = mtod(m, struct ieee80211_frame_rts *);
rts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
@@ -2468,7 +2728,7 @@
struct mbuf *m;
/* XXX honor ic_headroom */
- m = m_gethdr(M_DONTWAIT, MT_DATA);
+ m = m_gethdr(M_NOWAIT, MT_DATA);
if (m != NULL) {
cts = mtod(m, struct ieee80211_frame_cts *);
cts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
@@ -2485,9 +2745,9 @@
static void
ieee80211_tx_mgt_timeout(void *arg)
{
- struct ieee80211_node *ni = arg;
- struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211vap *vap = arg;
+ IEEE80211_LOCK(vap->iv_ic);
if (vap->iv_state != IEEE80211_S_INIT &&
(vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) {
/*
@@ -2494,11 +2754,26 @@
* NB: it's safe to specify a timeout as the reason here;
* it'll only be used in the right state.
*/
- ieee80211_new_state(vap, IEEE80211_S_SCAN,
+ ieee80211_new_state_locked(vap, IEEE80211_S_SCAN,
IEEE80211_SCAN_FAIL_TIMEOUT);
}
+ IEEE80211_UNLOCK(vap->iv_ic);
}
+/*
+ * This is the callback set on net80211-sourced transmitted
+ * authentication request frames.
+ *
+ * This does a couple of things:
+ *
+ * + If the frame transmitted was a success, it schedules a future
+ * event which will transition the interface to scan.
+ * If a state transition _then_ occurs before that event occurs,
+ * said state transition will cancel this callout.
+ *
+ * + If the frame transmit was a failure, it immediately schedules
+ * the transition back to scan.
+ */
static void
ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status)
{
@@ -2516,10 +2791,11 @@
*
* XXX what happens if !acked but response shows up before callback?
*/
- if (vap->iv_state == ostate)
+ if (vap->iv_state == ostate) {
callout_reset(&vap->iv_mgtsend,
status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
- ieee80211_tx_mgt_timeout, ni);
+ ieee80211_tx_mgt_timeout, vap);
+ }
}
static void
@@ -2617,29 +2893,32 @@
frm = ieee80211_add_powerconstraint(frm, vap);
bo->bo_csa = frm;
if (ic->ic_flags & IEEE80211_F_CSAPENDING)
- frm = ieee80211_add_csa(frm, vap);
+ frm = ieee80211_add_csa(frm, vap);
} else
bo->bo_csa = frm;
+
+ if (vap->iv_flags & IEEE80211_F_DOTH) {
+ bo->bo_quiet = frm;
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
+ if (vap->iv_quiet)
+ frm = ieee80211_add_quiet(frm,vap);
+ }
+ } else
+ bo->bo_quiet = frm;
+
if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
bo->bo_erp = frm;
frm = ieee80211_add_erp(frm, ic);
}
frm = ieee80211_add_xrates(frm, rs);
- if (vap->iv_flags & IEEE80211_F_WPA2) {
- if (vap->iv_rsn_ie != NULL)
- frm = add_ie(frm, vap->iv_rsn_ie);
- /* XXX else complain */
- }
+ frm = ieee80211_add_rsn(frm, vap);
if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
frm = ieee80211_add_htcap(frm, ni);
bo->bo_htinfo = frm;
frm = ieee80211_add_htinfo(frm, ni);
}
- if (vap->iv_flags & IEEE80211_F_WPA1) {
- if (vap->iv_wpa_ie != NULL)
- frm = add_ie(frm, vap->iv_wpa_ie);
- /* XXX else complain */
- }
+ frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME) {
bo->bo_wme = frm;
frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
@@ -2733,7 +3012,8 @@
+ 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */
+ IEEE80211_COUNTRY_MAX_SIZE /* country */
+ 2 + 1 /* power control */
- + sizeof(struct ieee80211_csa_ie) /* CSA */
+ + sizeof(struct ieee80211_csa_ie) /* CSA */
+ + sizeof(struct ieee80211_quiet_ie) /* Quiet */
+ 2 + 1 /* ERP */
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */
@@ -2766,7 +3046,7 @@
}
ieee80211_beacon_construct(m, frm, bo, ni);
- M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
KASSERT(m != NULL, ("no space for 802.11 header?"));
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
@@ -2953,6 +3233,7 @@
bo->bo_appie += adjust;
bo->bo_wme += adjust;
bo->bo_csa += adjust;
+ bo->bo_quiet += adjust;
bo->bo_tim_len = timlen;
/* update information element */
@@ -3006,6 +3287,7 @@
#endif
bo->bo_appie += sizeof(*csa);
bo->bo_csa_trailer_len += sizeof(*csa);
+ bo->bo_quiet += sizeof(*csa);
bo->bo_tim_trailer_len += sizeof(*csa);
m->m_len += sizeof(*csa);
m->m_pkthdr.len += sizeof(*csa);
@@ -3016,6 +3298,11 @@
vap->iv_csa_count++;
/* NB: don't clear IEEE80211_BEACON_CSA */
}
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){
+ if (vap->iv_quiet)
+ ieee80211_add_quiet(bo->bo_quiet, vap);
+ }
if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
/*
* ERP element needs updating.
@@ -3058,3 +3345,71 @@
return len_changed;
}
+
+/*
+ * Do Ethernet-LLC encapsulation for each payload in a fast frame
+ * tunnel encapsulation. The frame is assumed to have an Ethernet
+ * header at the front that must be stripped before prepending the
+ * LLC followed by the Ethernet header passed in (with an Ethernet
+ * type that specifies the payload size).
+ */
+struct mbuf *
+ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m,
+ const struct ether_header *eh)
+{
+ struct llc *llc;
+ uint16_t payload;
+
+ /* XXX optimize by combining m_adj+M_PREPEND */
+ m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
+ llc = mtod(m, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ llc->llc_snap.org_code[0] = 0;
+ llc->llc_snap.org_code[1] = 0;
+ llc->llc_snap.org_code[2] = 0;
+ llc->llc_snap.ether_type = eh->ether_type;
+ payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */
+
+ M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT);
+ if (m == NULL) { /* XXX cannot happen */
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
+ "%s: no space for ether_header\n", __func__);
+ vap->iv_stats.is_tx_nobuf++;
+ return NULL;
+ }
+ ETHER_HEADER_COPY(mtod(m, void *), eh);
+ mtod(m, struct ether_header *)->ether_type = htons(payload);
+ return m;
+}
+
+/*
+ * Complete an mbuf transmission.
+ *
+ * For now, this simply processes a completed frame after the
+ * driver has completed it's transmission and/or retransmission.
+ * It assumes the frame is an 802.11 encapsulated frame.
+ *
+ * Later on it will grow to become the exit path for a given frame
+ * from the driver and, depending upon how it's been encapsulated
+ * and already transmitted, it may end up doing A-MPDU retransmission,
+ * power save requeuing, etc.
+ *
+ * In order for the above to work, the driver entry point to this
+ * must not hold any driver locks. Thus, the driver needs to delay
+ * any actual mbuf completion until it can release said locks.
+ *
+ * This frees the mbuf and if the mbuf has a node reference,
+ * the node reference will be freed.
+ */
+void
+ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status)
+{
+
+ if (ni != NULL) {
+ if (m->m_flags & M_TXCB)
+ ieee80211_process_callback(ni, m, status);
+ ieee80211_free_node(ni);
+ }
+ m_freem(m);
+}
Modified: trunk/sys/net80211/ieee80211_phy.c
===================================================================
--- trunk/sys/net80211/ieee80211_phy.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_phy.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_phy.c 254315 2013-08-14 04:24:25Z rpaulo $");
/*
* IEEE 802.11 PHY-related support.
@@ -60,8 +61,11 @@
#define TURBO IEEE80211_T_TURBO
#define HALF IEEE80211_T_OFDM_HALF
#define QUART IEEE80211_T_OFDM_QUARTER
+#define HT IEEE80211_T_HT
+/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
+#define N(r) (IEEE80211_RATE_MCS | r)
#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */
-#define B(r) (0x80 | r)
+#define B(r) (IEEE80211_RATE_BASIC | r)
#define Mb(x) (x*1000)
static struct ieee80211_rate_table ieee80211_11b_table = {
@@ -176,6 +180,98 @@
},
};
+static struct ieee80211_rate_table ieee80211_11ng_table = {
+ .rateCount = 36,
+ .info = {
+/* short ctrl */
+/* Preamble dot11Rate Rate */
+ [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
+ [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
+ [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
+ [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
+ [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
+ [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
+ [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
+ [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
+ [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
+ [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
+ [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
+ [11] = { .phy = OFDM, 54000, 0x00, 108, 8 },
+
+ [12] = { .phy = HT, 6500, 0x00, N(0), 4 },
+ [13] = { .phy = HT, 13000, 0x00, N(1), 6 },
+ [14] = { .phy = HT, 19500, 0x00, N(2), 6 },
+ [15] = { .phy = HT, 26000, 0x00, N(3), 8 },
+ [16] = { .phy = HT, 39000, 0x00, N(4), 8 },
+ [17] = { .phy = HT, 52000, 0x00, N(5), 8 },
+ [18] = { .phy = HT, 58500, 0x00, N(6), 8 },
+ [19] = { .phy = HT, 65000, 0x00, N(7), 8 },
+
+ [20] = { .phy = HT, 13000, 0x00, N(8), 4 },
+ [21] = { .phy = HT, 26000, 0x00, N(9), 6 },
+ [22] = { .phy = HT, 39000, 0x00, N(10), 6 },
+ [23] = { .phy = HT, 52000, 0x00, N(11), 8 },
+ [24] = { .phy = HT, 78000, 0x00, N(12), 8 },
+ [25] = { .phy = HT, 104000, 0x00, N(13), 8 },
+ [26] = { .phy = HT, 117000, 0x00, N(14), 8 },
+ [27] = { .phy = HT, 130000, 0x00, N(15), 8 },
+
+ [28] = { .phy = HT, 19500, 0x00, N(16), 4 },
+ [29] = { .phy = HT, 39000, 0x00, N(17), 6 },
+ [30] = { .phy = HT, 58500, 0x00, N(18), 6 },
+ [31] = { .phy = HT, 78000, 0x00, N(19), 8 },
+ [32] = { .phy = HT, 117000, 0x00, N(20), 8 },
+ [33] = { .phy = HT, 156000, 0x00, N(21), 8 },
+ [34] = { .phy = HT, 175500, 0x00, N(22), 8 },
+ [35] = { .phy = HT, 195000, 0x00, N(23), 8 },
+
+ },
+};
+
+static struct ieee80211_rate_table ieee80211_11na_table = {
+ .rateCount = 32,
+ .info = {
+/* short ctrl */
+/* Preamble dot11Rate Rate */
+ [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
+ [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
+ [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
+ [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
+ [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
+ [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
+ [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
+ [7] = { .phy = OFDM, 54000, 0x00, 108, 4 },
+
+ [8] = { .phy = HT, 6500, 0x00, N(0), 0 },
+ [9] = { .phy = HT, 13000, 0x00, N(1), 2 },
+ [10] = { .phy = HT, 19500, 0x00, N(2), 2 },
+ [11] = { .phy = HT, 26000, 0x00, N(3), 4 },
+ [12] = { .phy = HT, 39000, 0x00, N(4), 4 },
+ [13] = { .phy = HT, 52000, 0x00, N(5), 4 },
+ [14] = { .phy = HT, 58500, 0x00, N(6), 4 },
+ [15] = { .phy = HT, 65000, 0x00, N(7), 4 },
+
+ [16] = { .phy = HT, 13000, 0x00, N(8), 0 },
+ [17] = { .phy = HT, 26000, 0x00, N(9), 2 },
+ [18] = { .phy = HT, 39000, 0x00, N(10), 2 },
+ [19] = { .phy = HT, 52000, 0x00, N(11), 4 },
+ [20] = { .phy = HT, 78000, 0x00, N(12), 4 },
+ [21] = { .phy = HT, 104000, 0x00, N(13), 4 },
+ [22] = { .phy = HT, 117000, 0x00, N(14), 4 },
+ [23] = { .phy = HT, 130000, 0x00, N(15), 4 },
+
+ [24] = { .phy = HT, 19500, 0x00, N(16), 0 },
+ [25] = { .phy = HT, 39000, 0x00, N(17), 2 },
+ [26] = { .phy = HT, 58500, 0x00, N(18), 2 },
+ [27] = { .phy = HT, 78000, 0x00, N(19), 4 },
+ [28] = { .phy = HT, 117000, 0x00, N(20), 4 },
+ [29] = { .phy = HT, 156000, 0x00, N(21), 4 },
+ [30] = { .phy = HT, 175500, 0x00, N(22), 4 },
+ [31] = { .phy = HT, 195000, 0x00, N(23), 4 },
+
+ },
+};
+
#undef Mb
#undef B
#undef OFDM
@@ -184,6 +280,8 @@
#undef CCK
#undef TURBO
#undef XR
+#undef HT
+#undef N
/*
* Setup a rate table's reverse lookup table and fill in
@@ -197,13 +295,12 @@
static void
ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
{
-#define N(a) (sizeof(a)/sizeof(a[0]))
#define WLAN_CTRL_FRAME_SIZE \
(sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
int i;
- for (i = 0; i < N(rt->rateCodeToIndex); i++)
+ for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
rt->rateCodeToIndex[i] = (uint8_t) -1;
for (i = 0; i < rt->rateCount; i++) {
uint8_t code = rt->info[i].dot11Rate;
@@ -210,15 +307,23 @@
uint8_t cix = rt->info[i].ctlRateIndex;
uint8_t ctl_rate = rt->info[cix].dot11Rate;
- rt->rateCodeToIndex[code] = i;
- if (code & IEEE80211_RATE_BASIC) {
- /*
- * Map w/o basic rate bit too.
- */
- code &= IEEE80211_RATE_VAL;
- rt->rateCodeToIndex[code] = i;
+ /*
+ * Map without the basic rate bit.
+ *
+ * It's up to the caller to ensure that the basic
+ * rate bit is stripped here.
+ *
+ * For HT, use the MCS rate bit.
+ */
+ code &= IEEE80211_RATE_VAL;
+ if (rt->info[i].phy == IEEE80211_T_HT) {
+ code |= IEEE80211_RATE_MCS;
}
+ /* XXX assume the control rate is non-MCS? */
+ ctl_rate &= IEEE80211_RATE_VAL;
+ rt->rateCodeToIndex[code] = i;
+
/*
* XXX for 11g the control rate to use for 5.5 and 11 Mb/s
* depends on whether they are marked as basic rates;
@@ -236,7 +341,6 @@
}
#undef WLAN_CTRL_FRAME_SIZE
-#undef N
}
/* Setup all rate tables */
@@ -243,15 +347,13 @@
static void
ieee80211_phy_init(void)
{
-#define N(arr) (int)(sizeof(arr) / sizeof(arr[0]))
static struct ieee80211_rate_table * const ratetables[] = {
&ieee80211_half_table,
&ieee80211_quarter_table,
- &ieee80211_11a_table,
- &ieee80211_11g_table,
+ &ieee80211_11na_table,
+ &ieee80211_11ng_table,
&ieee80211_turbog_table,
&ieee80211_turboa_table,
- &ieee80211_turboa_table,
&ieee80211_11a_table,
&ieee80211_11g_table,
&ieee80211_11b_table
@@ -258,10 +360,9 @@
};
int i;
- for (i = 0; i < N(ratetables); ++i)
+ for (i = 0; i < nitems(ratetables); ++i)
ieee80211_setup_ratetable(ratetables[i]);
-#undef N
}
SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
@@ -276,9 +377,9 @@
else if (IEEE80211_IS_CHAN_QUARTER(c))
rt = &ieee80211_quarter_table;
else if (IEEE80211_IS_CHAN_HTA(c))
- rt = &ieee80211_11a_table; /* XXX */
+ rt = &ieee80211_11na_table;
else if (IEEE80211_IS_CHAN_HTG(c))
- rt = &ieee80211_11g_table; /* XXX */
+ rt = &ieee80211_11ng_table;
else if (IEEE80211_IS_CHAN_108G(c))
rt = &ieee80211_turbog_table;
else if (IEEE80211_IS_CHAN_ST(c))
@@ -463,3 +564,66 @@
}
return txTime;
}
+
+static const uint16_t ht20_bps[32] = {
+ 26, 52, 78, 104, 156, 208, 234, 260,
+ 52, 104, 156, 208, 312, 416, 468, 520,
+ 78, 156, 234, 312, 468, 624, 702, 780,
+ 104, 208, 312, 416, 624, 832, 936, 1040
+};
+static const uint16_t ht40_bps[32] = {
+ 54, 108, 162, 216, 324, 432, 486, 540,
+ 108, 216, 324, 432, 648, 864, 972, 1080,
+ 162, 324, 486, 648, 972, 1296, 1458, 1620,
+ 216, 432, 648, 864, 1296, 1728, 1944, 2160
+};
+
+
+#define OFDM_PLCP_BITS 22
+#define HT_L_STF 8
+#define HT_L_LTF 8
+#define HT_L_SIG 4
+#define HT_SIG 8
+#define HT_STF 4
+#define HT_LTF(n) ((n) * 4)
+
+#define HT_RC_2_MCS(_rc) ((_rc) & 0xf)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS)
+
+/*
+ * Calculate the transmit duration of an 11n frame.
+ */
+uint32_t
+ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
+ int streams, int isht40, int isShortGI)
+{
+ uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
+
+ KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
+ KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
+
+ if (isht40)
+ bitsPerSymbol = ht40_bps[rate & 0x1f];
+ else
+ bitsPerSymbol = ht20_bps[rate & 0x1f];
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = howmany(numBits, bitsPerSymbol);
+ if (isShortGI)
+ txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */
+ else
+ txTime = numSymbols * 4; /* 4us */
+ return txTime + HT_L_STF + HT_L_LTF +
+ HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+}
+
+#undef IS_HT_RATE
+#undef HT_RC_2_STREAMS
+#undef HT_RC_2_MCS
+#undef HT_LTF
+#undef HT_STF
+#undef HT_SIG
+#undef HT_L_SIG
+#undef HT_L_LTF
+#undef HT_L_STF
+#undef OFDM_PLCP_BITS
Modified: trunk/sys/net80211/ieee80211_phy.h
===================================================================
--- trunk/sys/net80211/ieee80211_phy.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_phy.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_phy.h 252727 2013-07-04 21:16:49Z adrian $
*/
#ifndef _NET80211_IEEE80211_PHY_H_
@@ -60,6 +61,8 @@
struct ieee80211_channel;
+#define IEEE80211_RATE_TABLE_SIZE 128
+
struct ieee80211_rate_table {
int rateCount; /* NB: for proper padding */
uint8_t rateCodeToIndex[256]; /* back mapping */
@@ -74,7 +77,7 @@
* rate; used for dur. calcs */
uint16_t lpAckDuration; /* long preamble ACK dur. */
uint16_t spAckDuration; /* short preamble ACK dur. */
- } info[32];
+ } info[IEEE80211_RATE_TABLE_SIZE];
};
const struct ieee80211_rate_table *ieee80211_get_ratetable(
@@ -83,7 +86,14 @@
static __inline__ uint8_t
ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex;
KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[cix].dot11Rate;
}
@@ -91,7 +101,14 @@
static __inline__ uint8_t
ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex;
KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[cix].dot11Rate;
}
@@ -99,7 +116,14 @@
static __inline__ enum ieee80211_phytype
ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t rix = rt->rateCodeToIndex[rate];
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t rix = rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL];
KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[rix].phy;
}
@@ -107,6 +131,13 @@
static __inline__ int
ieee80211_isratevalid(const struct ieee80211_rate_table *rt, uint8_t rate)
{
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
return rt->rateCodeToIndex[rate] != (uint8_t)-1;
}
@@ -134,6 +165,14 @@
}
}
+static __inline__ uint8_t
+ieee80211_legacy_rate_lookup(const struct ieee80211_rate_table *rt,
+ uint8_t rate)
+{
+
+ return (rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]);
+}
+
/*
* Compute the time to transmit a frame of length frameLen bytes
* using the specified 802.11 rate code, phy, and short preamble
@@ -151,5 +190,10 @@
* Convert 802.11 rate code to PLCP signal.
*/
uint8_t ieee80211_rate2plcp(int, enum ieee80211_phytype);
+
+uint32_t ieee80211_compute_duration_ht(uint32_t frameLen,
+ uint16_t rate, int streams, int isht40,
+ int isShortGI);
+
#endif /* _KERNEL */
#endif /* !_NET80211_IEEE80211_PHY_H_ */
Modified: trunk/sys/net80211/ieee80211_power.c
===================================================================
--- trunk/sys/net80211/ieee80211_power.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_power.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD: src/sys/net80211/ieee80211_power.c,v 1.5 2013/01/17 23:29:38 laffer1 Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_power.c 254261 2013-08-12 22:27:53Z adrian $");
/*
* IEEE 802.11 power save support.
@@ -69,6 +70,8 @@
vap->iv_update_ps = ieee80211_update_ps;
vap->iv_set_tim = ieee80211_set_tim;
}
+ vap->iv_node_ps = ieee80211_node_pwrsave;
+ vap->iv_sta_ps = ieee80211_sta_pwrsave;
}
void
@@ -411,9 +414,12 @@
pwrsave_flushq(struct ieee80211_node *ni)
{
struct ieee80211_psq *psq = &ni->ni_psq;
+ struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_psq_head *qhead;
struct ifnet *parent, *ifp;
+ struct mbuf *parent_q = NULL, *ifp_q = NULL;
+ struct mbuf *m;
IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
"flush ps queue, %u packets queued", psq->psq_len);
@@ -425,8 +431,7 @@
parent = vap->iv_ic->ic_ifp;
/* XXX need different driver interface */
/* XXX bypasses q max and OACTIVE */
- IF_PREPEND_LIST(&parent->if_snd, qhead->head, qhead->tail,
- qhead->len);
+ parent_q = qhead->head;
qhead->head = qhead->tail = NULL;
qhead->len = 0;
} else
@@ -437,8 +442,7 @@
ifp = vap->iv_ifp;
/* XXX need different driver interface */
/* XXX bypasses q max and OACTIVE */
- IF_PREPEND_LIST(&ifp->if_snd, qhead->head, qhead->tail,
- qhead->len);
+ ifp_q = qhead->head;
qhead->head = qhead->tail = NULL;
qhead->len = 0;
} else
@@ -448,10 +452,36 @@
/* NB: do this outside the psq lock */
/* XXX packets might get reordered if parent is OACTIVE */
- if (parent != NULL)
- if_start(parent);
- if (ifp != NULL)
- if_start(ifp);
+ /* parent frames, should be encapsulated */
+ if (parent != NULL) {
+ while (parent_q != NULL) {
+ m = parent_q;
+ parent_q = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ /* must be encapsulated */
+ KASSERT((m->m_flags & M_ENCAP),
+ ("%s: parentq with non-M_ENCAP frame!\n",
+ __func__));
+ /*
+ * For encaped frames, we need to free the node
+ * reference upon failure.
+ */
+ if (ieee80211_parent_xmitpkt(ic, m) != 0)
+ ieee80211_free_node(ni);
+ }
+ }
+
+ /* VAP frames, aren't encapsulated */
+ if (ifp != NULL) {
+ while (ifp_q != NULL) {
+ m = ifp_q;
+ ifp_q = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ KASSERT((!(m->m_flags & M_ENCAP)),
+ ("%s: vapq with M_ENCAP frame!\n", __func__));
+ (void) ieee80211_vap_xmitpkt(vap, m);
+ }
+ }
}
/*
Modified: trunk/sys/net80211/ieee80211_power.h
===================================================================
--- trunk/sys/net80211/ieee80211_power.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_power.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_power.h 241138 2012-10-02 17:45:19Z adrian $
*/
#ifndef _NET80211_IEEE80211_POWER_H_
#define _NET80211_IEEE80211_POWER_H_
@@ -71,6 +72,11 @@
struct mbuf *ieee80211_node_psq_dequeue(struct ieee80211_node *ni, int *qlen);
int ieee80211_node_psq_drain(struct ieee80211_node *);
int ieee80211_node_psq_age(struct ieee80211_node *);
+
+/*
+ * Don't call these directly from the stack; they are vap methods
+ * that should be overridden.
+ */
int ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *);
void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
void ieee80211_sta_pwrsave(struct ieee80211vap *, int enable);
Modified: trunk/sys/net80211/ieee80211_proto.c
===================================================================
--- trunk/sys/net80211/ieee80211_proto.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_proto.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_proto.c 314667 2017-03-04 13:03:31Z avg $");
/*
* IEEE 802.11 protocol support.
@@ -105,9 +106,8 @@
static void update_mcast(void *, int);
static void update_promisc(void *, int);
static void update_channel(void *, int);
+static void update_chw(void *, int);
static void ieee80211_newstate_cb(void *, int);
-static int ieee80211_new_state_locked(struct ieee80211vap *,
- enum ieee80211_state, int);
static int
null_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
@@ -144,6 +144,7 @@
TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic);
TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic);
TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic);
+ TASK_INIT(&ic->ic_chw_task, 0, update_chw, ic);
ic->ic_wme.wme_hipri_switch_hysteresis =
AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
@@ -193,8 +194,8 @@
vap->iv_rtsthreshold = IEEE80211_RTS_DEFAULT;
vap->iv_fragthreshold = IEEE80211_FRAG_DEFAULT;
vap->iv_bmiss_max = IEEE80211_BMISS_MAX;
- callout_init(&vap->iv_swbmiss, CALLOUT_MPSAFE);
- callout_init(&vap->iv_mgtsend, CALLOUT_MPSAFE);
+ callout_init_mtx(&vap->iv_swbmiss, IEEE80211_LOCK_OBJ(ic), 0);
+ callout_init(&vap->iv_mgtsend, 1);
TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, vap);
TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap);
/*
@@ -447,7 +448,7 @@
printf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID,
qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : "");
}
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
int off;
off = ieee80211_anyhdrspace(ic, wh);
@@ -660,13 +661,12 @@
int
ieee80211_iserp_rateset(const struct ieee80211_rateset *rs)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 };
int i, j;
- if (rs->rs_nrates < N(rates))
+ if (rs->rs_nrates < nitems(rates))
return 0;
- for (i = 0; i < N(rates); i++) {
+ for (i = 0; i < nitems(rates); i++) {
for (j = 0; j < rs->rs_nrates; j++) {
int r = rs->rs_rates[j] & IEEE80211_RATE_VAL;
if (rates[i] == r)
@@ -679,7 +679,6 @@
;
}
return 1;
-#undef N
}
/*
@@ -994,6 +993,7 @@
struct wmeParams *chanp, *bssp;
enum ieee80211_phymode mode;
int i;
+ int do_aggrmode = 0;
/*
* Set up the channel access parameters for the physical
@@ -1034,11 +1034,38 @@
* BE uses agressive params to optimize performance of
* legacy/non-QoS traffic.
*/
- if ((vap->iv_opmode == IEEE80211_M_HOSTAP &&
- (wme->wme_flags & WME_F_AGGRMODE) != 0) ||
- (vap->iv_opmode == IEEE80211_M_STA &&
- (vap->iv_bss->ni_flags & IEEE80211_NODE_QOS) == 0) ||
- (vap->iv_flags & IEEE80211_F_WME) == 0) {
+
+ /* Hostap? Only if aggressive mode is enabled */
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+ (wme->wme_flags & WME_F_AGGRMODE) != 0)
+ do_aggrmode = 1;
+
+ /*
+ * Station? Only if we're in a non-QoS BSS.
+ */
+ else if ((vap->iv_opmode == IEEE80211_M_STA &&
+ (vap->iv_bss->ni_flags & IEEE80211_NODE_QOS) == 0))
+ do_aggrmode = 1;
+
+ /*
+ * IBSS? Only if we we have WME enabled.
+ */
+ else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
+ (vap->iv_flags & IEEE80211_F_WME))
+ do_aggrmode = 1;
+
+ /*
+ * If WME is disabled on this VAP, default to aggressive mode
+ * regardless of the configuration.
+ */
+ if ((vap->iv_flags & IEEE80211_F_WME) == 0)
+ do_aggrmode = 1;
+
+ /* XXX WDS? */
+
+ /* XXX MBSS? */
+
+ if (do_aggrmode) {
chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
@@ -1056,7 +1083,14 @@
chanp->wmep_acm, chanp->wmep_aifsn, chanp->wmep_logcwmin,
chanp->wmep_logcwmax, chanp->wmep_txopLimit);
}
-
+
+
+ /*
+ * Change the contention window based on the number of associated
+ * stations. If the number of associated stations is 1 and
+ * aggressive mode is enabled, lower the contention window even
+ * further.
+ */
if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
static const uint8_t logCwMin[IEEE80211_MODE_MAX] = {
@@ -1080,8 +1114,15 @@
IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
"update %s (chan+bss) logcwmin %u\n",
ieee80211_wme_acnames[WME_AC_BE], chanp->wmep_logcwmin);
- }
- if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */
+ }
+
+ /*
+ * Arrange for the beacon update.
+ *
+ * XXX what about MBSS, WDS?
+ */
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP
+ || vap->iv_opmode == IEEE80211_M_IBSS) {
/*
* Arrange for a beacon update and bump the parameter
* set number so associated stations load the new values.
@@ -1147,6 +1188,17 @@
ieee80211_radiotap_chan_change(ic);
}
+static void
+update_chw(void *arg, int npending)
+{
+ struct ieee80211com *ic = arg;
+
+ /*
+ * XXX should we defer the channel width _config_ update until now?
+ */
+ ic->ic_update_chw(ic);
+}
+
/*
* Block until the parent is in a known state. This is
* used after any operations that dispatch a task (e.g.
@@ -1161,6 +1213,7 @@
ieee80211_draintask(ic, &ic->ic_promisc_task);
ieee80211_draintask(ic, &ic->ic_chan_task);
ieee80211_draintask(ic, &ic->ic_bmiss_task);
+ ieee80211_draintask(ic, &ic->ic_chw_task);
taskqueue_unblock(ic->ic_tq);
}
@@ -1403,7 +1456,7 @@
struct ieee80211com *ic = arg;
struct ieee80211vap *vap;
- /* XXX locking */
+ IEEE80211_LOCK(ic);
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
/*
* We only pass events through for sta vap's in RUN state;
@@ -1415,6 +1468,7 @@
vap->iv_bmiss != NULL)
vap->iv_bmiss(vap);
}
+ IEEE80211_UNLOCK(ic);
}
static void
@@ -1421,12 +1475,14 @@
beacon_swmiss(void *arg, int npending)
{
struct ieee80211vap *vap = arg;
+ struct ieee80211com *ic = vap->iv_ic;
- if (vap->iv_state != IEEE80211_S_RUN)
- return;
-
- /* XXX Call multiple times if npending > zero? */
- vap->iv_bmiss(vap);
+ IEEE80211_LOCK(ic);
+ if (vap->iv_state == IEEE80211_S_RUN) {
+ /* XXX Call multiple times if npending > zero? */
+ vap->iv_bmiss(vap);
+ }
+ IEEE80211_UNLOCK(ic);
}
/*
@@ -1440,6 +1496,8 @@
struct ieee80211vap *vap = arg;
struct ieee80211com *ic = vap->iv_ic;
+ IEEE80211_LOCK_ASSERT(ic);
+
/* XXX sleep state? */
KASSERT(vap->iv_state == IEEE80211_S_RUN,
("wrong state %d", vap->iv_state));
@@ -1610,6 +1668,7 @@
if (vap->iv_state != IEEE80211_S_INIT) {
/* NB: iv_newstate may drop the lock */
vap->iv_newstate(vap, IEEE80211_S_INIT, 0);
+ IEEE80211_LOCK_ASSERT(ic);
vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT;
}
}
@@ -1644,6 +1703,7 @@
vap->iv_newstate(vap,
vap->iv_opmode == IEEE80211_M_STA ?
IEEE80211_S_SCAN : IEEE80211_S_RUN, 0);
+ IEEE80211_LOCK_ASSERT(ic);
}
}
}
@@ -1673,6 +1733,7 @@
ieee80211_state_name[vap->iv_state],
ieee80211_state_name[IEEE80211_S_INIT], arg);
vap->iv_newstate(vap, IEEE80211_S_INIT, arg);
+ IEEE80211_LOCK_ASSERT(ic);
vap->iv_flags_ext &= ~IEEE80211_FEXT_REINIT;
}
@@ -1694,6 +1755,7 @@
ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg);
rc = vap->iv_newstate(vap, nstate, arg);
+ IEEE80211_LOCK_ASSERT(ic);
vap->iv_flags_ext &= ~IEEE80211_FEXT_STATEWAIT;
if (rc != 0) {
/* State transition failed */
@@ -1720,8 +1782,11 @@
* (i.e. coming out of power save mode).
*/
vap->iv_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- if_start(vap->iv_ifp);
+ /*
+ * XXX TODO Kick-start a VAP queue - this should be a method!
+ */
+
/* bring up any vaps waiting on us */
wakeupwaiting(vap);
} else if (nstate == IEEE80211_S_INIT) {
@@ -1733,8 +1798,9 @@
*/
ieee80211_scan_flush(vap);
- /* XXX NB: cast for altq */
- ieee80211_flush_ifq((struct ifqueue *)&ic->ic_ifp->if_snd, vap);
+ /*
+ * XXX TODO: ic/vap queue flush
+ */
}
done:
IEEE80211_UNLOCK(ic);
@@ -1767,7 +1833,7 @@
* is usually a mistake and indicates lack of proper integration
* with the net80211 layer.
*/
-static int
+int
ieee80211_new_state_locked(struct ieee80211vap *vap,
enum ieee80211_state nstate, int arg)
{
Modified: trunk/sys/net80211/ieee80211_proto.h
===================================================================
--- trunk/sys/net80211/ieee80211_proto.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_proto.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_proto.h 259175 2013-12-10 13:42:59Z gavin $
*/
#ifndef _NET80211_IEEE80211_PROTO_H_
#define _NET80211_IEEE80211_PROTO_H_
@@ -96,12 +97,22 @@
struct ieee80211_bpf_params *);
int ieee80211_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
+#if __FreeBSD_version >= 1000031
int ieee80211_output(struct ifnet *, struct mbuf *,
+ const struct sockaddr *, struct route *ro);
+#else
+int ieee80211_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct route *ro);
+#endif
+int ieee80211_vap_pkt_send_dest(struct ieee80211vap *, struct mbuf *,
+ struct ieee80211_node *);
+int ieee80211_raw_output(struct ieee80211vap *, struct ieee80211_node *,
+ struct mbuf *, const struct ieee80211_bpf_params *);
void ieee80211_send_setup(struct ieee80211_node *, struct mbuf *, int, int,
const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN],
const uint8_t [IEEE80211_ADDR_LEN]);
-void ieee80211_start(struct ifnet *);
+int ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m);
+void ieee80211_vap_qflush(struct ifnet *ifp);
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_classify(struct ieee80211_node *, struct mbuf *m);
struct mbuf *ieee80211_mbuf_adjust(struct ieee80211vap *, int,
@@ -115,6 +126,11 @@
const uint8_t da[IEEE80211_ADDR_LEN],
const uint8_t bssid[IEEE80211_ADDR_LEN],
const uint8_t *ssid, size_t ssidlen);
+struct mbuf * ieee80211_ff_encap1(struct ieee80211vap *, struct mbuf *,
+ const struct ether_header *);
+void ieee80211_tx_complete(struct ieee80211_node *,
+ struct mbuf *, int);
+
/*
* The formation of ProbeResponse frames requires guidance to
* deal with legacy clients. When the client is identified as
@@ -134,6 +150,9 @@
uint8_t *ieee80211_add_rates(uint8_t *, const struct ieee80211_rateset *);
uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *);
+uint8_t *ieee80211_add_wpa(uint8_t *, const struct ieee80211vap *);
+uint8_t *ieee80211_add_rsn(uint8_t *, const struct ieee80211vap *);
+uint8_t *ieee80211_add_qos(uint8_t *, const struct ieee80211_node *);
uint16_t ieee80211_getcapinfo(struct ieee80211vap *,
struct ieee80211_channel *);
@@ -215,7 +234,7 @@
int (*iac_attach)(struct ieee80211vap *);
void (*iac_detach)(struct ieee80211vap *);
int (*iac_check)(struct ieee80211vap *,
- const uint8_t mac[IEEE80211_ADDR_LEN]);
+ const struct ieee80211_frame *wh);
int (*iac_add)(struct ieee80211vap *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
int (*iac_remove)(struct ieee80211vap *,
@@ -314,6 +333,8 @@
void ieee80211_swbmiss(void *arg);
void ieee80211_beacon_miss(struct ieee80211com *);
int ieee80211_new_state(struct ieee80211vap *, enum ieee80211_state, int);
+int ieee80211_new_state_locked(struct ieee80211vap *, enum ieee80211_state,
+ int);
void ieee80211_print_essid(const uint8_t *, int);
void ieee80211_dump_pkt(struct ieee80211com *,
const uint8_t *, int, int, int);
@@ -344,6 +365,7 @@
uint16_t bo_appie_len; /* AppIE length in bytes */
uint16_t bo_csa_trailer_len;
uint8_t *bo_csa; /* start of CSA element */
+ uint8_t *bo_quiet; /* start of Quiet element */
uint8_t *bo_meshconf; /* start of MESHCONF element */
uint8_t *bo_spare[3];
};
Modified: trunk/sys/net80211/ieee80211_radiotap.c
===================================================================
--- trunk/sys/net80211/ieee80211_radiotap.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_radiotap.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_radiotap.c 237214 2012-06-18 02:08:04Z adrian $");
/*
* IEEE 802.11 radiotap support.
@@ -47,7 +48,7 @@
#include <net80211/ieee80211_var.h>
-static int radiotap_offset(struct ieee80211_radiotap_header *, int);
+static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
void
ieee80211_radiotap_attach(struct ieee80211com *ic,
@@ -54,6 +55,17 @@
struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
{
+ ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
+ rh, rlen, 0, rx_radiotap);
+}
+
+void
+ieee80211_radiotap_attachv(struct ieee80211com *ic,
+ struct ieee80211_radiotap_header *th,
+ int tlen, int n_tx_v, uint32_t tx_radiotap,
+ struct ieee80211_radiotap_header *rh,
+ int rlen, int n_rx_v, uint32_t rx_radiotap)
+{
#define B(_v) (1<<(_v))
int off;
@@ -63,11 +75,11 @@
/* calculate offset to channel data */
off = -1;
if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
- off = radiotap_offset(th, IEEE80211_RADIOTAP_CHANNEL);
+ off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
- off = radiotap_offset(th, IEEE80211_RADIOTAP_XCHANNEL);
+ off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
if (off == -1) {
- if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x",
+ if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x\n",
__func__, tx_radiotap);
/* NB: we handle this case but data will have no chan spec */
} else
@@ -79,11 +91,11 @@
/* calculate offset to channel data */
off = -1;
if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
- off = radiotap_offset(rh, IEEE80211_RADIOTAP_CHANNEL);
+ off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
- off = radiotap_offset(rh, IEEE80211_RADIOTAP_XCHANNEL);
+ off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
if (off == -1) {
- if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x",
+ if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x\n",
__func__, rx_radiotap);
/* NB: we handle this case but data will have no chan spec */
} else
@@ -260,7 +272,8 @@
* known -1 is returned.
*/
static int
-radiotap_offset(struct ieee80211_radiotap_header *rh, int item)
+radiotap_offset(struct ieee80211_radiotap_header *rh,
+ int n_vendor_attributes, int item)
{
static const struct {
size_t align, width;
@@ -325,11 +338,17 @@
.align = sizeof(uint32_t),
.width = 2*sizeof(uint32_t),
},
+ [IEEE80211_RADIOTAP_MCS] = {
+ .align = sizeof(uint8_t),
+ .width = 3*sizeof(uint8_t),
+ },
};
uint32_t present = le32toh(rh->it_present);
int off, i;
off = sizeof(struct ieee80211_radiotap_header);
+ off += n_vendor_attributes * (sizeof(uint32_t));
+
for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
if ((present & (1<<i)) == 0)
continue;
Modified: trunk/sys/net80211/ieee80211_radiotap.h
===================================================================
--- trunk/sys/net80211/ieee80211_radiotap.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_radiotap.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,4 +1,5 @@
/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/net80211/ieee80211_radiotap.h 245156 2013-01-08 06:59:21Z adrian $ */
/* $NetBSD: ieee80211_radiotap.h,v 1.16 2007/01/06 05:51:15 dyoung Exp $ */
/*-
@@ -54,6 +55,12 @@
#define IEEE80211_RADIOTAP_HDRLEN 64 /* XXX deprecated */
+struct ieee80211_radiotap_vendor_header {
+ uint8_t vh_oui[3]; /* 3 byte vendor OUI */
+ uint8_t vh_sub_ns; /* Sub namespace of this section */
+ uint16_t vh_skip_len; /* Length of this vendor section */
+} __packed;
+
/*
* The radio capture header precedes the 802.11 header.
*
@@ -188,8 +195,21 @@
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
- /* NB: gap for netbsd definitions */
+ /*
+ * 14-17 are from Linux, they overlap the netbsd-specific
+ * fields.
+ */
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+
IEEE80211_RADIOTAP_XCHANNEL = 18,
+ IEEE80211_RADIOTAP_MCS = 19,
+ IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+
+ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
+ IEEE80211_RADIOTAP_VENDOREXT = 30,
IEEE80211_RADIOTAP_EXT = 31,
};
Modified: trunk/sys/net80211/ieee80211_ratectl.c
===================================================================
--- trunk/sys/net80211/ieee80211_ratectl.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ratectl.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo at FreeBSD.org>
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ratectl.c 214894 2010-11-06 18:17:20Z bschmidt $");
#include <sys/param.h>
#include <sys/kernel.h>
Modified: trunk/sys/net80211/ieee80211_ratectl.h
===================================================================
--- trunk/sys/net80211/ieee80211_ratectl.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ratectl.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo at FreeBSD.org>
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_ratectl.h 215289 2010-11-14 09:59:52Z bschmidt $
*/
enum ieee80211_ratealgs {
Modified: trunk/sys/net80211/ieee80211_ratectl_none.c
===================================================================
--- trunk/sys/net80211/ieee80211_ratectl_none.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_ratectl_none.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2010 Bernhard Schmidt <bschmidt at FreeBSD.org>
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_ratectl_none.c 215244 2010-11-13 14:59:54Z bschmidt $");
#include "opt_wlan.h"
Modified: trunk/sys/net80211/ieee80211_regdomain.c
===================================================================
--- trunk/sys/net80211/ieee80211_regdomain.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_regdomain.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_regdomain.c 233845 2012-04-03 17:48:42Z bschmidt $");
/*
* IEEE 802.11 regdomain support.
@@ -105,7 +106,12 @@
c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
c->ic_ieee = ieee;
c->ic_flags = flags;
- c->ic_extieee = 0;
+ if (flags & IEEE80211_CHAN_HT40U)
+ c->ic_extieee = ieee + 4;
+ else if (flags & IEEE80211_CHAN_HT40D)
+ c->ic_extieee = ieee - 4;
+ else
+ c->ic_extieee = 0;
}
/*
@@ -123,7 +129,8 @@
/* XXX just do something for now */
ic->ic_nchans = 0;
if (isset(bands, IEEE80211_MODE_11B) ||
- isset(bands, IEEE80211_MODE_11G)) {
+ isset(bands, IEEE80211_MODE_11G) ||
+ isset(bands, IEEE80211_MODE_11NG)) {
int maxchan = 11;
if (rd != NULL && rd->ecm)
maxchan = 14;
@@ -132,15 +139,67 @@
addchan(ic, i, IEEE80211_CHAN_B);
if (isset(bands, IEEE80211_MODE_11G))
addchan(ic, i, IEEE80211_CHAN_G);
+ if (isset(bands, IEEE80211_MODE_11NG)) {
+ addchan(ic, i,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
+ }
+ if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
+ continue;
+ if (i <= 7) {
+ addchan(ic, i,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
+ addchan(ic, i + 4,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
+ }
}
}
- if (isset(bands, IEEE80211_MODE_11A)) {
- for (i = 36; i <= 64; i += 4)
+ if (isset(bands, IEEE80211_MODE_11A) ||
+ isset(bands, IEEE80211_MODE_11NA)) {
+ for (i = 36; i <= 64; i += 4) {
addchan(ic, i, IEEE80211_CHAN_A);
- for (i = 100; i <= 140; i += 4)
+ if (isset(bands, IEEE80211_MODE_11NA)) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+ }
+ if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
+ continue;
+ if ((i % 8) == 4) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+ addchan(ic, i + 4,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+ }
+ }
+ for (i = 100; i <= 140; i += 4) {
addchan(ic, i, IEEE80211_CHAN_A);
- for (i = 149; i <= 161; i += 4)
+ if (isset(bands, IEEE80211_MODE_11NA)) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+ }
+ if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
+ continue;
+ if ((i % 8) == 4 && i != 140) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+ addchan(ic, i + 4,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+ }
+ }
+ for (i = 149; i <= 161; i += 4) {
addchan(ic, i, IEEE80211_CHAN_A);
+ if (isset(bands, IEEE80211_MODE_11NA)) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+ }
+ if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
+ continue;
+ if ((i % 8) == 5) {
+ addchan(ic, i,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+ addchan(ic, i + 4,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+ }
+ }
}
if (rd != NULL)
ic->ic_regdomain = *rd;
Modified: trunk/sys/net80211/ieee80211_regdomain.h
===================================================================
--- trunk/sys/net80211/ieee80211_regdomain.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_regdomain.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_regdomain.h 243974 2012-12-07 06:34:46Z adrian $
*/
#ifndef _NET80211_IEEE80211_REGDOMAIN_H_
#define _NET80211_IEEE80211_REGDOMAIN_H_
@@ -258,6 +259,17 @@
SKU_SR9 = 0x0298, /* Ubiquiti SR9 (900MHz/GSM) */
SKU_XR9 = 0x0299, /* Ubiquiti XR9 (900MHz/GSM) */
SKU_GZ901 = 0x029a, /* Zcomax GZ-901 (900MHz/GSM) */
+ SKU_XC900M = 0x029b, /* Xagyl XC900M (900MHz/GSM) */
+ /*
+ * The XC900M by default uses the
+ * same mapping as the XR9. It
+ * can optionally use a slightly
+ * offset channel spacing (905MHz-
+ * 925MHz) versus the XR9 (907MHz-
+ * 922MHz), giving an extra channel.
+ * This requires a jumper on the
+ * NIC to be changed.
+ */
};
#if defined(__KERNEL__) || defined(_KERNEL)
Modified: trunk/sys/net80211/ieee80211_rssadapt.c
===================================================================
--- trunk/sys/net80211/ieee80211_rssadapt.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_rssadapt.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,4 +1,5 @@
-/* $MidnightBSD$ */
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/net80211/ieee80211_rssadapt.c 321725 2017-07-30 18:38:05Z avos $ */
/* $NetBSD: ieee80211_rssadapt.c,v 1.9 2005/02/26 22:45:09 perry Exp $ */
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo at FreeBSD.org>
@@ -127,7 +128,8 @@
KASSERT(vap->iv_rs == NULL, ("%s: iv_rs already initialized",
__func__));
-
+
+ nrefs++; /* XXX locking */
vap->iv_rs = rs = malloc(sizeof(struct ieee80211_rssadapt),
M_80211_RATECTL, M_NOWAIT|M_ZERO);
if (rs == NULL) {
@@ -143,6 +145,8 @@
rssadapt_deinit(struct ieee80211vap *vap)
{
free(vap->iv_rs, M_80211_RATECTL);
+ KASSERT(nrefs > 0, ("imbalanced attach/detach"));
+ nrefs--; /* XXX locking */
}
static void
Modified: trunk/sys/net80211/ieee80211_rssadapt.h
===================================================================
--- trunk/sys/net80211/ieee80211_rssadapt.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_rssadapt.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,4 +1,5 @@
-/* $MidnightBSD$ */
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/net80211/ieee80211_rssadapt.h 206358 2010-04-07 15:29:13Z rpaulo $ */
/* $NetBSD: ieee80211_rssadapt.h,v 1.4 2005/02/26 22:45:09 perry Exp $ */
/*-
* Copyright (c) 2003, 2004 David Young. All rights reserved.
Modified: trunk/sys/net80211/ieee80211_scan.c
===================================================================
--- trunk/sys/net80211/ieee80211_scan.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_scan.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_scan.c 259173 2013-12-10 13:36:56Z gavin $");
/*
* IEEE 802.11 scanning support.
@@ -859,6 +860,7 @@
if (ss->ss_next == ss->ss_last) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: no channels to scan\n", __func__);
+ scandone = 1;
goto done;
}
@@ -866,7 +868,7 @@
vap->iv_state == IEEE80211_S_RUN) {
if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
/* Enable station power save mode */
- ieee80211_sta_pwrsave(vap, 1);
+ vap->iv_sta_ps(vap, 1);
/*
* Use an 1ms delay so the null data frame has a chance
* to go out.
@@ -960,6 +962,19 @@
IEEE80211_LOCK(ic);
/*
+ * Since a cancellation may have occured during one of the
+ * driver calls (whilst unlocked), update scandone.
+ */
+ if (scandone == 0 &&
+ ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) {
+ /* XXX printf? */
+ if_printf(vap->iv_ifp,
+ "%s: OOPS! scan cancelled during driver call!\n",
+ __func__);
+ }
+ scandone |= ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0);
+
+ /*
* Record scan complete time. Note that we also do
* this when canceled so any background scan will
* not be restarted for a while.
@@ -1034,7 +1049,7 @@
* waiting for us.
*/
if (scandone) {
- ieee80211_sta_pwrsave(vap, 0);
+ vap->iv_sta_ps(vap, 0);
if (ss->ss_next >= ss->ss_last) {
ieee80211_notify_scan_done(vap);
ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
Modified: trunk/sys/net80211/ieee80211_scan.h
===================================================================
--- trunk/sys/net80211/ieee80211_scan.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_scan.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_scan.h 227331 2011-11-08 04:00:24Z adrian $
*/
#ifndef _NET80211_IEEE80211_SCAN_H_
#define _NET80211_IEEE80211_SCAN_H_
@@ -213,6 +214,7 @@
uint8_t *ath;
uint8_t *tdma;
uint8_t *csa;
+ uint8_t *quiet;
uint8_t *meshid;
uint8_t *meshconf;
uint8_t *spare[3];
Modified: trunk/sys/net80211/ieee80211_scan_sta.c
===================================================================
--- trunk/sys/net80211/ieee80211_scan_sta.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_scan_sta.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_scan_sta.c 254315 2013-08-14 04:24:25Z rpaulo $");
/*
* IEEE 802.11 station scanning support.
@@ -51,6 +52,7 @@
#ifdef IEEE80211_SUPPORT_MESH
#include <net80211/ieee80211_mesh.h>
#endif
+#include <net80211/ieee80211_ratectl.h>
#include <net/bpf.h>
@@ -449,13 +451,12 @@
struct ieee80211_scan_state *ss,
enum ieee80211_phymode mode, const uint16_t freq[], int nfreq)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_channel *c, *cg;
u_int modeflags;
int i;
- KASSERT(mode < N(chanflags), ("Unexpected mode %u", mode));
+ KASSERT(mode < nitems(chanflags), ("Unexpected mode %u", mode));
modeflags = chanflags[mode];
for (i = 0; i < nfreq; i++) {
if (ss->ss_last >= IEEE80211_SCAN_MAX)
@@ -475,7 +476,6 @@
}
ss->ss_chans[ss->ss_last++] = c;
}
-#undef N
}
struct scanlist {
@@ -1567,6 +1567,7 @@
struct sta_table *st = ss->ss_priv;
struct sta_entry *selbs;
struct ieee80211_channel *chan;
+ struct ieee80211com *ic = vap->iv_ic;
KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
vap->iv_opmode == IEEE80211_M_AHDEMO ||
@@ -1612,15 +1613,19 @@
*/
if (vap->iv_des_chan == IEEE80211_CHAN_ANYC ||
IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
- struct ieee80211com *ic = vap->iv_ic;
-
chan = adhoc_pick_channel(ss, 0);
- if (chan != NULL)
- chan = ieee80211_ht_adjust_channel(ic,
- chan, vap->iv_flags_ht);
} else
chan = vap->iv_des_chan;
if (chan != NULL) {
+ struct ieee80211com *ic = vap->iv_ic;
+ /*
+ * Create a HT capable IBSS; the per-node
+ * probe request/response will result in
+ * "correct" rate control capabilities being
+ * negotiated.
+ */
+ chan = ieee80211_ht_adjust_channel(ic,
+ chan, vap->iv_flags_ht);
ieee80211_create_ibss(vap, chan);
return 1;
}
@@ -1644,6 +1649,14 @@
chan = selbs->base.se_chan;
if (selbs->se_flags & STA_DEMOTE11B)
chan = demote11b(vap, chan);
+ /*
+ * If HT is available, make it a possibility here.
+ * The intent is to enable HT20/HT40 when joining a non-HT
+ * IBSS node; we can then advertise HT IEs and speak HT
+ * to any subsequent nodes that support it.
+ */
+ chan = ieee80211_ht_adjust_channel(ic,
+ chan, vap->iv_flags_ht);
if (!ieee80211_sta_join(vap, chan, &selbs->base))
goto notfound;
return 1; /* terminate scan */
Modified: trunk/sys/net80211/ieee80211_sta.c
===================================================================
--- trunk/sys/net80211/ieee80211_sta.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_sta.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_sta.c 262007 2014-02-17 01:36:53Z kevlo $");
#endif
/*
@@ -50,6 +51,8 @@
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_llc.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
#include <net/ethernet.h>
#include <net/bpf.h>
@@ -61,6 +64,7 @@
#include <net80211/ieee80211_superg.h>
#endif
#include <net80211/ieee80211_ratectl.h>
+#include <net80211/ieee80211_sta.h>
#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
@@ -109,6 +113,8 @@
{
struct ieee80211com *ic = vap->iv_ic;
+ IEEE80211_LOCK_ASSERT(ic);
+
KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
KASSERT(vap->iv_state >= IEEE80211_S_RUN,
("wrong state %s", ieee80211_state_name[vap->iv_state]));
@@ -398,7 +404,7 @@
arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
break;
case IEEE80211_S_SLEEP:
- ieee80211_sta_pwrsave(vap, 0);
+ vap->iv_sta_ps(vap, 0);
break;
default:
goto invalid;
@@ -434,7 +440,7 @@
goto invalid;
break;
case IEEE80211_S_SLEEP:
- ieee80211_sta_pwrsave(vap, 1);
+ vap->iv_sta_ps(vap, 1);
break;
default:
invalid:
@@ -582,6 +588,30 @@
vap->iv_stats.is_rx_wrongbss++;
goto out;
}
+
+ /*
+ * Some devices may be in a promiscuous mode
+ * where they receive frames for multiple station
+ * addresses.
+ *
+ * If we receive a data frame that isn't
+ * destined to our VAP MAC, drop it.
+ *
+ * XXX TODO: This is only enforced when not scanning;
+ * XXX it assumes a software-driven scan will put the NIC
+ * XXX into a "no data frames" mode before setting this
+ * XXX flag. Otherwise it may be possible that we'll still
+ * XXX process data frames whilst scanning.
+ */
+ if ((! IEEE80211_IS_MULTICAST(wh->i_addr1))
+ && (! IEEE80211_ADDR_EQ(wh->i_addr1, IF_LLADDR(ifp)))) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+ bssid, NULL, "not to cur sta: lladdr=%6D, addr1=%6D",
+ IF_LLADDR(ifp), ":", wh->i_addr1, ":");
+ vap->iv_stats.is_rx_wrongbss++;
+ goto out;
+ }
+
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
if (HAS_SEQ(type) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
@@ -699,7 +729,7 @@
* crypto cipher modules used to do delayed update
* of replay sequence numbers.
*/
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
/*
* Discard encrypted frames when privacy is off.
@@ -717,7 +747,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
} else {
/* XXX M_WEP and IEEE80211_F_PRIVACY */
key = NULL;
@@ -852,7 +882,7 @@
ether_sprintf(wh->i_addr2), rssi);
}
#endif
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
/*
* Only shared key auth frames with a challenge
@@ -881,7 +911,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
}
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
goto out;
@@ -1058,7 +1088,7 @@
IEEE80211_SCAN_FAIL_STATUS);
}
-static int
+int
ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
const struct ieee80211_frame *wh)
{
@@ -1257,6 +1287,7 @@
uint8_t *frm, *efrm;
uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
uint8_t rate;
+ int ht_state_change = 0;
wh = mtod(m0, struct ieee80211_frame *);
frm = (uint8_t *)&wh[1];
@@ -1277,8 +1308,11 @@
return;
}
/* XXX probe response in sta mode when !scanning? */
- if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
+ if (ieee80211_parse_beacon(ni, m0, &scan) != 0) {
+ if (! (ic->ic_flags & IEEE80211_F_SCAN))
+ vap->iv_stats.is_beacon_bad++;
return;
+ }
/*
* Count frame now that we know it's to be processed.
*/
@@ -1341,10 +1375,13 @@
#endif
if (scan.htcap != NULL && scan.htinfo != NULL &&
(vap->iv_flags_ht & IEEE80211_FHT_HT)) {
- ieee80211_ht_updateparams(ni,
- scan.htcap, scan.htinfo);
/* XXX state changes? */
+ if (ieee80211_ht_updateparams(ni,
+ scan.htcap, scan.htinfo))
+ ht_state_change = 1;
}
+ if (scan.quiet)
+ ic->ic_set_quiet(ni, scan.quiet);
if (scan.tim != NULL) {
struct ieee80211_tim_ie *tim =
(struct ieee80211_tim_ie *) scan.tim;
@@ -1361,7 +1398,7 @@
* we are expecting data.
*/
ic->ic_lastdata = ticks;
- ieee80211_sta_pwrsave(vap, 0);
+ vap->iv_sta_ps(vap, 0);
}
#endif
ni->ni_dtim_count = tim->tim_count;
@@ -1408,6 +1445,13 @@
#endif
ieee80211_bg_scan(vap, 0);
}
+
+ /*
+ * If we've had a channel width change (eg HT20<->HT40)
+ * then schedule a delayed driver notification.
+ */
+ if (ht_state_change)
+ ieee80211_update_chw(ic);
return;
}
/*
Modified: trunk/sys/net80211/ieee80211_sta.h
===================================================================
--- trunk/sys/net80211/ieee80211_sta.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_sta.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_sta.h 244060 2012-12-09 22:56:29Z adrian $
*/
#ifndef _NET80211_IEEE80211_STA_H_
#define _NET80211_IEEE80211_STA_H_
@@ -33,4 +34,10 @@
void ieee80211_sta_attach(struct ieee80211com *);
void ieee80211_sta_detach(struct ieee80211com *);
void ieee80211_sta_vattach(struct ieee80211vap *);
+
+/*
+ * Used by the adhoc/mesh/tdma paths.
+ */
+extern int ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
+ const struct ieee80211_frame *wh);
#endif /* !_NET80211_IEEE80211_STA_H_ */
Modified: trunk/sys/net80211/ieee80211_superg.c
===================================================================
--- trunk/sys/net80211/ieee80211_superg.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_superg.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -24,10 +25,12 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_superg.c 273736 2014-10-27 14:38:00Z hselasky $");
#include "opt_wlan.h"
+#ifdef IEEE80211_SUPPORT_SUPERG
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -84,7 +87,7 @@
memcpy(dst, src, sizeof(struct ether_header))
static int ieee80211_ffppsmin = 2; /* pps threshold for ff aggregation */
-SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLFLAG_RW,
&ieee80211_ffppsmin, 0, "min packet rate before fast-frame staging");
static int ieee80211_ffagemax = -1; /* max time frames held on stage q */
SYSCTL_PROC(_net_wlan, OID_AUTO, ffagemax, CTLTYPE_INT | CTLFLAG_RW,
@@ -328,43 +331,6 @@
}
/*
- * Do Ethernet-LLC encapsulation for each payload in a fast frame
- * tunnel encapsulation. The frame is assumed to have an Ethernet
- * header at the front that must be stripped before prepending the
- * LLC followed by the Ethernet header passed in (with an Ethernet
- * type that specifies the payload size).
- */
-static struct mbuf *
-ff_encap1(struct ieee80211vap *vap, struct mbuf *m,
- const struct ether_header *eh)
-{
- struct llc *llc;
- uint16_t payload;
-
- /* XXX optimize by combining m_adj+M_PREPEND */
- m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
- llc = mtod(m, struct llc *);
- llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
- llc->llc_control = LLC_UI;
- llc->llc_snap.org_code[0] = 0;
- llc->llc_snap.org_code[1] = 0;
- llc->llc_snap.org_code[2] = 0;
- llc->llc_snap.ether_type = eh->ether_type;
- payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */
-
- M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
- if (m == NULL) { /* XXX cannot happen */
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
- "%s: no space for ether_header\n", __func__);
- vap->iv_stats.is_tx_nobuf++;
- return NULL;
- }
- ETHER_HEADER_COPY(mtod(m, void *), eh);
- mtod(m, struct ether_header *)->ether_type = htons(payload);
- return m;
-}
-
-/*
* Fast frame encapsulation. There must be two packets
* chained with m_nextpkt. We do header adjustment for
* each, add the tunnel encapsulation, and then concatenate
@@ -422,10 +388,10 @@
* Now do tunnel encapsulation. First, each
* frame gets a standard encapsulation.
*/
- m1 = ff_encap1(vap, m1, &eh1);
+ m1 = ieee80211_ff_encap1(vap, m1, &eh1);
if (m1 == NULL)
goto bad;
- m2 = ff_encap1(vap, m2, &eh2);
+ m2 = ieee80211_ff_encap1(vap, m2, &eh2);
if (m2 == NULL)
goto bad;
@@ -460,7 +426,7 @@
*/
m->m_next = m2; /* NB: last mbuf from above */
m1->m_pkthdr.len += m2->m_pkthdr.len;
- M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT);
+ M_PREPEND(m1, sizeof(uint32_t)+2, M_NOWAIT);
if (m1 == NULL) { /* XXX cannot happen */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
"%s: no space for tunnel header\n", __func__);
@@ -469,7 +435,7 @@
}
memset(mtod(m1, void *), 0, sizeof(uint32_t)+2);
- M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT);
+ M_PREPEND(m1, sizeof(struct llc), M_NOWAIT);
if (m1 == NULL) { /* XXX cannot happen */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
"%s: no space for llc header\n", __func__);
@@ -499,15 +465,17 @@
ff_transmit(struct ieee80211_node *ni, struct mbuf *m)
{
struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
int error;
+ IEEE80211_TX_LOCK_ASSERT(vap->iv_ic);
+
/* encap and xmit */
m = ieee80211_encap(vap, ni, m);
if (m != NULL) {
struct ifnet *ifp = vap->iv_ifp;
- struct ifnet *parent = ni->ni_ic->ic_ifp;
- error = parent->if_transmit(parent, m);
+ error = ieee80211_parent_xmitpkt(ic, m);;
if (error != 0) {
/* NB: IFQ_HANDOFF reclaims mbuf */
ieee80211_free_node(ni);
@@ -547,30 +515,40 @@
/*
* Age frames on the staging queue.
+ *
+ * This is called without the comlock held, but it does all its work
+ * behind the comlock. Because of this, it's possible that the
+ * staging queue will be serviced between the function which called
+ * it and now; thus simply checking that the queue has work in it
+ * may fail.
+ *
+ * See PR kern/174283 for more details.
*/
void
ieee80211_ff_age(struct ieee80211com *ic, struct ieee80211_stageq *sq,
int quanta)
{
- struct ieee80211_superg *sg = ic->ic_superg;
struct mbuf *m, *head;
struct ieee80211_node *ni;
struct ieee80211_tx_ampdu *tap;
+#if 0
KASSERT(sq->head != NULL, ("stageq empty"));
+#endif
IEEE80211_LOCK(ic);
head = sq->head;
while ((m = sq->head) != NULL && M_AGE_GET(m) < quanta) {
+ int tid = WME_AC_TO_TID(M_WME_GETAC(m));
+
/* clear tap ref to frame */
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
- tap = &ni->ni_tx_ampdu[M_WME_GETAC(m)];
+ tap = &ni->ni_tx_ampdu[tid];
KASSERT(tap->txa_private == m, ("staging queue empty"));
tap->txa_private = NULL;
sq->head = m->m_nextpkt;
sq->depth--;
- sg->ff_stageqdepth--;
}
if (m == NULL)
sq->tail = NULL;
@@ -578,13 +556,18 @@
M_AGE_SUB(m, quanta);
IEEE80211_UNLOCK(ic);
+ IEEE80211_TX_LOCK(ic);
ff_flush(head, m);
+ IEEE80211_TX_UNLOCK(ic);
}
static void
-stageq_add(struct ieee80211_stageq *sq, struct mbuf *m)
+stageq_add(struct ieee80211com *ic, struct ieee80211_stageq *sq, struct mbuf *m)
{
int age = ieee80211_ffagemax;
+
+ IEEE80211_LOCK_ASSERT(ic);
+
if (sq->tail != NULL) {
sq->tail->m_nextpkt = m;
age -= M_AGE_GET(sq->head);
@@ -598,10 +581,12 @@
}
static void
-stageq_remove(struct ieee80211_stageq *sq, struct mbuf *mstaged)
+stageq_remove(struct ieee80211com *ic, struct ieee80211_stageq *sq, struct mbuf *mstaged)
{
struct mbuf *m, *mprev;
+ IEEE80211_LOCK_ASSERT(ic);
+
mprev = NULL;
for (m = sq->head; m != NULL; m = m->m_nextpkt) {
if (m == mstaged) {
@@ -662,6 +647,8 @@
struct mbuf *mstaged;
uint32_t txtime, limit;
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+
/*
* Check if the supplied frame can be aggregated.
*
@@ -670,7 +657,7 @@
* be aggregated with other types of frames when encryption is on?
*/
IEEE80211_LOCK(ic);
- tap = &ni->ni_tx_ampdu[pri];
+ tap = &ni->ni_tx_ampdu[WME_AC_TO_TID(pri)];
mstaged = tap->txa_private; /* NB: we reuse AMPDU state */
ieee80211_txampdu_count_packet(tap);
@@ -713,14 +700,16 @@
tap->txa_private = NULL;
if (mstaged != NULL)
- stageq_remove(sq, mstaged);
+ stageq_remove(ic, sq, mstaged);
IEEE80211_UNLOCK(ic);
if (mstaged != NULL) {
+ IEEE80211_TX_LOCK(ic);
IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
"%s: flush staged frame", __func__);
/* encap and xmit */
ff_transmit(ni, mstaged);
+ IEEE80211_TX_UNLOCK(ic);
}
return m; /* NB: original frame */
}
@@ -733,7 +722,7 @@
*/
if (mstaged != NULL) {
tap->txa_private = NULL;
- stageq_remove(sq, mstaged);
+ stageq_remove(ic, sq, mstaged);
IEEE80211_UNLOCK(ic);
IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
@@ -754,8 +743,7 @@
("txa_private %p", tap->txa_private));
tap->txa_private = m;
- stageq_add(sq, m);
- sg->ff_stageqdepth++;
+ stageq_add(ic, sq, m);
IEEE80211_UNLOCK(ic);
IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
@@ -782,17 +770,19 @@
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_superg *sg = ic->ic_superg;
struct ieee80211_tx_ampdu *tap;
- struct mbuf *m, *head;
- int ac;
+ struct mbuf *m, *next_m, *head;
+ int tid;
IEEE80211_LOCK(ic);
head = NULL;
- for (ac = 0; ac < WME_NUM_AC; ac++) {
- tap = &ni->ni_tx_ampdu[ac];
+ for (tid = 0; tid < WME_NUM_TID; tid++) {
+ int ac = TID_TO_WME_AC(tid);
+
+ tap = &ni->ni_tx_ampdu[tid];
m = tap->txa_private;
if (m != NULL) {
tap->txa_private = NULL;
- stageq_remove(&sg->ff_stageq[ac], m);
+ stageq_remove(ic, &sg->ff_stageq[ac], m);
m->m_nextpkt = head;
head = m;
}
@@ -799,9 +789,16 @@
}
IEEE80211_UNLOCK(ic);
- for (m = head; m != NULL; m = m->m_nextpkt) {
+ /*
+ * Free mbufs, taking care to not dereference the mbuf after
+ * we free it (hence grabbing m_nextpkt before we free it.)
+ */
+ m = head;
+ while (m != NULL) {
+ next_m = m->m_nextpkt;
m_freem(m);
ieee80211_free_node(ni);
+ m = next_m;
}
}
@@ -898,3 +895,5 @@
return 0;
}
IEEE80211_IOCTL_SET(superg, superg_ioctl_set80211);
+
+#endif /* IEEE80211_SUPPORT_SUPERG */
Modified: trunk/sys/net80211/ieee80211_superg.h
===================================================================
--- trunk/sys/net80211/ieee80211_superg.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_superg.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_superg.h 244051 2012-12-09 19:20:28Z adrian $
*/
#ifndef _NET80211_IEEE80211_SUPERG_H_
#define _NET80211_IEEE80211_SUPERG_H_
@@ -66,7 +67,6 @@
struct ieee80211_superg {
/* fast-frames staging q */
struct ieee80211_stageq ff_stageq[WME_NUM_AC];
- int ff_stageqdepth; /* cumulative depth */
};
void ieee80211_superg_attach(struct ieee80211com *);
@@ -87,6 +87,10 @@
void ieee80211_ff_age(struct ieee80211com *, struct ieee80211_stageq *,
int quanta);
+/*
+ * See ieee80211_ff_age() for a description of the locking
+ * expectation here.
+ */
static __inline void
ieee80211_ff_flush(struct ieee80211com *ic, int ac)
{
@@ -96,12 +100,16 @@
ieee80211_ff_age(ic, &sg->ff_stageq[ac], 0x7fffffff);
}
+/*
+ * See ieee80211_ff_age() for a description of the locking
+ * expectation here.
+ */
static __inline void
ieee80211_ff_age_all(struct ieee80211com *ic, int quanta)
{
struct ieee80211_superg *sg = ic->ic_superg;
- if (sg != NULL && sg->ff_stageqdepth) {
+ if (sg != NULL) {
if (sg->ff_stageq[WME_AC_VO].depth)
ieee80211_ff_age(ic, &sg->ff_stageq[WME_AC_VO], quanta);
if (sg->ff_stageq[WME_AC_VI].depth)
Modified: trunk/sys/net80211/ieee80211_tdma.c
===================================================================
--- trunk/sys/net80211/ieee80211_tdma.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_tdma.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Intel Corporation
@@ -26,7 +27,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_tdma.c 254506 2013-08-18 23:40:30Z adrian $");
#endif
/*
@@ -36,6 +37,8 @@
#include "opt_tdma.h"
#include "opt_wlan.h"
+#ifdef IEEE80211_SUPPORT_TDMA
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -286,6 +289,8 @@
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
+
KASSERT((vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
KASSERT(vap->iv_state == IEEE80211_S_RUN,
("wrong state %d", vap->iv_state));
@@ -740,7 +745,7 @@
struct ieee80211_tdma_state *ts = vap->iv_tdma;
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
- return EOPNOTSUPP;
+ return ENOSYS;
switch (ireq->i_type) {
case IEEE80211_IOC_TDMA_SLOT:
@@ -768,7 +773,7 @@
struct ieee80211_tdma_state *ts = vap->iv_tdma;
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
- return EOPNOTSUPP;
+ return ENOSYS;
switch (ireq->i_type) {
case IEEE80211_IOC_TDMA_SLOT:
@@ -818,3 +823,5 @@
return ERESTART;
}
IEEE80211_IOCTL_SET(tdma, tdma_ioctl_set80211);
+
+#endif /* IEEE80211_SUPPORT_TDMA */
Modified: trunk/sys/net80211/ieee80211_tdma.h
===================================================================
--- trunk/sys/net80211/ieee80211_tdma.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_tdma.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Intel Corporation
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_tdma.h 192468 2009-05-20 20:00:40Z sam $
*/
#ifndef _NET80211_IEEE80211_TDMA_H_
#define _NET80211_IEEE80211_TDMA_H_
Modified: trunk/sys/net80211/ieee80211_var.h
===================================================================
--- trunk/sys/net80211/ieee80211_var.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_var.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
@@ -23,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_var.h 254076 2013-08-07 22:01:43Z adrian $
*/
#ifndef _NET80211_IEEE80211_VAR_H_
#define _NET80211_IEEE80211_VAR_H_
@@ -55,7 +56,7 @@
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_scan.h>
-#define IEEE80211_TXPOWER_MAX 100 /* .5 dbM (XXX units?) */
+#define IEEE80211_TXPOWER_MAX 100 /* .5 dBm (XXX units?) */
#define IEEE80211_TXPOWER_MIN 0 /* kill radio */
#define IEEE80211_DTIM_DEFAULT 1 /* default DTIM period */
@@ -118,6 +119,7 @@
struct ieee80211com {
struct ifnet *ic_ifp; /* associated device */
ieee80211_com_lock_t ic_comlock; /* state update lock */
+ ieee80211_tx_lock_t ic_txlock; /* ic/vap TX lock */
TAILQ_HEAD(, ieee80211vap) ic_vaps; /* list of vap instances */
int ic_headroom; /* driver tx headroom needs */
enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */
@@ -130,6 +132,7 @@
struct task ic_mcast_task; /* deferred mcast update */
struct task ic_chan_task; /* deferred channel change */
struct task ic_bmiss_task; /* deferred beacon miss hndlr */
+ struct task ic_chw_task; /* deferred HT CHW update */
uint32_t ic_flags; /* state flags */
uint32_t ic_flags_ext; /* extended state flags */
@@ -242,6 +245,10 @@
int (*ic_setregdomain)(struct ieee80211com *,
struct ieee80211_regdomain *,
int, struct ieee80211_channel []);
+
+ int (*ic_set_quiet)(struct ieee80211_node *,
+ u_int8_t *quiet_elm);
+
/* send/recv 802.11 management frame */
int (*ic_send_mgmt)(struct ieee80211_node *,
int, int);
@@ -318,6 +325,10 @@
int batimeout, int baseqctl);
void (*ic_ampdu_rx_stop)(struct ieee80211_node *,
struct ieee80211_rx_ampdu *);
+
+ /* The channel width has changed (20<->2040) */
+ void (*ic_update_chw)(struct ieee80211com *);
+
uint64_t ic_spare[7];
};
@@ -403,6 +414,12 @@
uint8_t iv_dtim_period; /* DTIM period */
uint8_t iv_dtim_count; /* DTIM count from last bcn */
/* set/unset aid pwrsav state */
+ uint8_t iv_quiet; /* Quiet Element */
+ uint8_t iv_quiet_count; /* constant count for Quiet Element */
+ uint8_t iv_quiet_count_value; /* variable count for Quiet Element */
+ uint8_t iv_quiet_period; /* period for Quiet Element */
+ uint16_t iv_quiet_duration; /* duration for Quiet Element */
+ uint16_t iv_quiet_offset; /* offset for Quiet Element */
int iv_csa_count; /* count for doing CSA */
struct ieee80211_node *iv_bss; /* information for this node */
@@ -471,12 +488,22 @@
/* power save handling */
void (*iv_update_ps)(struct ieee80211vap *, int);
int (*iv_set_tim)(struct ieee80211_node *, int);
+ void (*iv_node_ps)(struct ieee80211_node *, int);
+ void (*iv_sta_ps)(struct ieee80211vap *, int);
+ void (*iv_recv_pspoll)(struct ieee80211_node *,
+ struct mbuf *);
+
/* state machine processing */
int (*iv_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
/* 802.3 output method for raw frame xmit */
+#if __FreeBSD_version >= 1000031
int (*iv_output)(struct ifnet *, struct mbuf *,
+ const struct sockaddr *, struct route *);
+#else
+ int (*iv_output)(struct ifnet *, struct mbuf *,
struct sockaddr *, struct route *);
+#endif
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);
@@ -690,6 +717,11 @@
uint32_t tx_radiotap,
struct ieee80211_radiotap_header *rh, int rlen,
uint32_t rx_radiotap);
+void ieee80211_radiotap_attachv(struct ieee80211com *,
+ struct ieee80211_radiotap_header *th,
+ int tlen, int n_tx_v, uint32_t tx_radiotap,
+ struct ieee80211_radiotap_header *rh,
+ int rlen, int n_rx_v, uint32_t rx_radiotap);
void ieee80211_radiotap_detach(struct ieee80211com *);
void ieee80211_radiotap_vattach(struct ieee80211vap *);
void ieee80211_radiotap_vdetach(struct ieee80211vap *);
@@ -796,6 +828,28 @@
}
/*
+ * Fetch the current TX power (cap) for the given node.
+ *
+ * This includes the node and ic/vap TX power limit as needed,
+ * but it doesn't take into account any per-rate limit.
+ */
+static __inline uint16_t
+ieee80211_get_node_txpower(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ uint16_t txpower;
+
+ txpower = ni->ni_txpower;
+ txpower = MIN(txpower, ic->ic_txpowlimit);
+ if (ic->ic_curchan != NULL) {
+ txpower = MIN(txpower, 2 * ic->ic_curchan->ic_maxregpower);
+ txpower = MIN(txpower, ic->ic_curchan->ic_maxpower);
+ }
+
+ return (txpower);
+}
+
+/*
* Debugging facilities compiled in when IEEE80211_DEBUG is defined.
*
* The intent is that any problem in the net80211 layer can be
Modified: trunk/sys/net80211/ieee80211_wds.c
===================================================================
--- trunk/sys/net80211/ieee80211_wds.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_wds.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -25,7 +26,7 @@
#include <sys/cdefs.h>
#ifdef __FreeBSD__
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_wds.c 283855 2015-05-31 23:29:04Z ae $");
#endif
/*
@@ -232,7 +233,6 @@
ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
{
struct ieee80211com *ic = vap0->iv_ic;
- struct ifnet *parent = ic->ic_ifp;
const struct ether_header *eh = mtod(m, const struct ether_header *);
struct ieee80211_node *ni;
struct ieee80211vap *vap;
@@ -256,7 +256,7 @@
/*
* Duplicate the frame and send it.
*/
- mcopy = m_copypacket(m, M_DONTWAIT);
+ mcopy = m_copypacket(m, M_NOWAIT);
if (mcopy == NULL) {
ifp->if_oerrors++;
/* XXX stat + msg */
@@ -296,13 +296,17 @@
mcopy->m_flags |= M_MCAST;
mcopy->m_pkthdr.rcvif = (void *) ni;
- err = parent->if_transmit(parent, mcopy);
+ err = ieee80211_parent_xmitpkt(ic, mcopy);
if (err) {
/* NB: IFQ_HANDOFF reclaims mbuf */
ifp->if_oerrors++;
ieee80211_free_node(ni);
- } else
+ } else {
ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
+ if_inc_counter(ifp, IFCOUNTER_OBYTES,
+ m->m_pkthdr.len);
+ }
}
}
@@ -557,7 +561,7 @@
* crypto cipher modules used to do delayed update
* of replay sequence numbers.
*/
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {
/*
* Discard encrypted frames when privacy is off.
@@ -575,7 +579,7 @@
goto out;
}
wh = mtod(m, struct ieee80211_frame *);
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
} else {
/* XXX M_WEP and IEEE80211_F_PRIVACY */
key = NULL;
@@ -709,7 +713,7 @@
ether_sprintf(wh->i_addr2), rssi);
}
#endif
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, NULL, "%s", "WEP set but not permitted");
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
Modified: trunk/sys/net80211/ieee80211_wds.h
===================================================================
--- trunk/sys/net80211/ieee80211_wds.h 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_wds.h 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/net80211/ieee80211_wds.h 178354 2008-04-20 20:35:46Z sam $
*/
#ifndef _NET80211_IEEE80211_WDS_H_
#define _NET80211_IEEE80211_WDS_H_
Modified: trunk/sys/net80211/ieee80211_xauth.c
===================================================================
--- trunk/sys/net80211/ieee80211_xauth.c 2018-05-25 20:03:57 UTC (rev 9936)
+++ trunk/sys/net80211/ieee80211_xauth.c 2018-05-25 20:04:31 UTC (rev 9937)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004 Video54 Technologies, Inc.
* Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/net80211/ieee80211_xauth.c 178354 2008-04-20 20:35:46Z sam $");
/*
* External authenticator placeholder module.
More information about the Midnightbsd-cvs
mailing list