PERFORCE change 65686 for review

Sam Leffler sam at FreeBSD.org
Tue Nov 23 03:54:55 GMT 2004


http://perforce.freebsd.org/chv.cgi?CH=65686

Change 65686 by sam at sam_ebb on 2004/11/23 03:54:00

	o checkpoint wme support (basic operation works for sta+ap)
	o cleanup power-save queue code for portability
	o synchronize beacon frame updates

Affected files ...

.. //depot/projects/wifi/sys/net80211/ieee80211.c#11 edit
.. //depot/projects/wifi/sys/net80211/ieee80211.h#4 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#6 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#16 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#17 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#11 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.c#18 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.h#11 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_output.c#10 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_proto.c#8 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_proto.h#7 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_var.h#13 edit

Differences ...

==== //depot/projects/wifi/sys/net80211/ieee80211.c#11 (text+ko) ====

@@ -159,11 +159,19 @@
 		ic->ic_curmode = IEEE80211_MODE_AUTO;
 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;	/* any channel is ok */
 
+	/*
+	 * Enable WME by default if we're capable.
+	 */
+	if (ic->ic_caps & IEEE80211_C_WME)
+		ic->ic_flags |= IEEE80211_F_WME;
+
 	(void) ieee80211_setmode(ic, ic->ic_curmode);
 
 	if (ic->ic_lintval == 0)
 		ic->ic_lintval = 100;		/* default sleep */
 	ic->ic_bmisstimeout = 7*ic->ic_lintval;	/* default 7 beacons */
+	IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
+
 	ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
 
 	ieee80211_node_attach(ic);
@@ -187,6 +195,8 @@
 	ieee80211_node_detach(ic);
 	ifmedia_removeall(&ic->ic_media);
 
+	IEEE80211_BEACON_LOCK_DESTROY(ic);
+
 	bpfdetach(ifp);
 	ether_ifdetach(ifp);
 }
@@ -603,6 +613,7 @@
 		 * is setup appropriately.
 		 */
 		ieee80211_reset_erp(ic);
+		ieee80211_wme_initparams(ic);	/* after opmode change */
 		error = ENETRESET;
 	}
 #ifdef notdef
@@ -834,6 +845,7 @@
 
 	ic->ic_curmode = mode;
 	ieee80211_reset_erp(ic);	/* reset ERP state */
+	ieee80211_wme_initparams(ic);	/* reset WME stat */
 
 	return 0;
 #undef N

==== //depot/projects/wifi/sys/net80211/ieee80211.h#4 (text+ko) ====

@@ -171,9 +171,11 @@
 
 #define	IEEE80211_QOS_TXOP			0x00ff
 /* bit 8 is reserved */
-#define	IEEE80211_QOS_ACKPOLICY			0x0600
-#define	IEEE80211_QOS_ESOP			0x0800
-#define	IEEE80211_QOS_TID			0xf000
+#define	IEEE80211_QOS_ACKPOLICY			0x60
+#define	IEEE80211_QOS_ACKPOLICY_S		5
+#define	IEEE80211_QOS_ESOP			0x10
+#define	IEEE80211_QOS_ESOP_S			4
+#define	IEEE80211_QOS_TID			0x0f
 
 /* does frame have QoS sequence control data */
 #define	IEEE80211_QOS_HAS_SEQ(wh) \
@@ -184,14 +186,14 @@
 /*
  * WME/802.11e information element.
  */
-struct ieee80211_ie_wme {
+struct ieee80211_wme_info {
 	u_int8_t	wme_id;		/* IEEE80211_ELEMID_VENDOR */
 	u_int8_t	wme_len;	/* length in bytes */
 	u_int8_t	wme_oui[3];	/* 0x00, 0x50, 0xf2 */
 	u_int8_t	wme_type;	/* OUI type */
 	u_int8_t	wme_subtype;	/* OUI subtype */
 	u_int8_t	wme_version;	/* spec revision */
-	u_int8_t	wme_info;	/* AC info */
+	u_int8_t	wme_info;	/* QoS info */
 } __packed;
 
 /*
@@ -223,6 +225,56 @@
 } __packed;
 
 /*
+ * WME AC parameter field
+ */
+struct ieee80211_wme_acparams {
+	u_int8_t	acp_aci_aifsn;
+	u_int8_t	acp_logcwminmax;
+	u_int16_t	acp_txop;
+} __packed;
+
+#define WME_NUM_AC		4	/* 4 AC categories */
+
+#define WME_PARAM_ACI		0x60	/* Mask for ACI field */
+#define WME_PARAM_ACI_S		5	/* Shift for ACI field */
+#define WME_PARAM_ACM		0x10	/* Mask for ACM bit */
+#define WME_PARAM_ACM_S		4	/* Shift for ACM bit */
+#define WME_PARAM_AIFSN		0x0f	/* Mask for aifsn field */
+#define WME_PARAM_AIFSN_S	0	/* Shift for aifsn field */
+#define WME_PARAM_LOGCWMIN	0x0f	/* Mask for CwMin field (in log) */
+#define WME_PARAM_LOGCWMIN_S	0	/* Shift for CwMin field */
+#define WME_PARAM_LOGCWMAX	0xf0	/* Mask for CwMax field (in log) */
+#define WME_PARAM_LOGCWMAX_S	4	/* Shift for CwMax field */
+
+#define WME_AC_TO_TID(_ac) (       \
+	((_ac) == WME_AC_VO) ? 6 : \
+	((_ac) == WME_AC_VI) ? 5 : \
+	((_ac) == WME_AC_BK) ? 1 : \
+	0)
+
+#define TID_TO_WME_AC(_tid) (      \
+	((_tid) < 1) ? WME_AC_BE : \
+	((_tid) < 3) ? WME_AC_BK : \
+	((_tid) < 6) ? WME_AC_VI : \
+	WME_AC_VO)
+
+/*
+ * WME Parameter Element
+ */
+struct ieee80211_wme_param {
+	u_int8_t	param_id;
+	u_int8_t	param_len;
+	u_int8_t	param_oui[3];
+	u_int8_t	param_oui_type;
+	u_int8_t	param_oui_sybtype;
+	u_int8_t	param_version;
+	u_int8_t	param_qosInfo;
+#define	WME_QOSINFO_COUNT	0x0f	/* Mask for param count field */
+	u_int8_t	param_reserved;
+	struct ieee80211_wme_acparams	params_acParams[WME_NUM_AC];
+} __packed;
+
+/*
  * Management Notification Frame
  */
 struct ieee80211_mnf {
@@ -461,6 +513,8 @@
 
 #define	WME_OUI			0xf25000
 #define	WME_OUI_TYPE		0x02
+#define	WME_INFO_OUI_SUBTYPE	0x00
+#define	WME_PARAM_OUI_SUBTYPE	0x01
 #define	WME_VERSION		1
 
 /* WME stream classes */

==== //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#6 (text+ko) ====

@@ -30,6 +30,18 @@
 #define _NET80211_IEEE80211_FREEBSD_H_
 
 /*
+ * Beacon locking definitions.
+ */
+typedef struct mtx ieee80211_beacon_lock_t;
+#define	IEEE80211_BEACON_LOCK_INIT(_ic, _name) \
+	mtx_init(&(_ic)->ic_beaconlock, _name, "802.11 beacon lock", MTX_DEF)
+#define	IEEE80211_BEACON_LOCK_DESTROY(_ic) mtx_destroy(&(_ic)->ic_beaconlock)
+#define	IEEE80211_BEACON_LOCK(_ic)	   mtx_lock(&(_ic)->ic_beaconlock)
+#define	IEEE80211_BEACON_UNLOCK(_ic)	   mtx_unlock(&(_ic)->ic_beaconlock)
+#define	IEEE80211_BEACON_LOCK_ASSERT(_ic) \
+	mtx_assert(&(_ic)->ic_beaconlock, MA_OWNED)
+
+/*
  * Node locking definitions.
  */
 typedef struct mtx ieee80211_node_lock_t;
@@ -42,6 +54,30 @@
 	mtx_assert(&(_nt)->nt_nodelock, MA_OWNED)
 
 /*
+ * Per-node power-save queue definitions. 
+ */
+#define	IEEE80211_NODE_SAVEQ_INIT(_ni, _name) do {		\
+	mtx_init(&(_ni)->ni_savedq.ifq_mtx, _name, "802.11 ps queue", MTX_DEF);\
+	(_ni)->ni_savedq.ifq_maxlen = IEEE80211_PS_MAX_QUEUE;	\
+} while (0)
+#define	IEEE80211_NODE_SAVEQ_DESTROY(_ni) \
+	mtx_destroy(&(_ni)->ni_savedq.ifq_mtx)
+#define	IEEE80211_NODE_SAVEQ_QLEN(_ni) \
+	_IF_QLEN(&(_ni)->ni_savedq)
+#define	IEEE80211_NODE_SAVEQ_DEQUEUE(_ni, _m, _qlen) do {	\
+	IF_LOCK(&(_ni)->ni_savedq);				\
+	_IF_DEQUEUE(&(_ni)->ni_savedq, _m);			\
+	(_qlen) = _IF_QLEN(&(_ni)->ni_savedq);			\
+	IF_UNLOCK(&(_ni)->ni_savedq);				\
+} while (0)
+#define	IEEE80211_NODE_SAVEQ_DRAIN(_ni, _qlen) do {		\
+	IF_LOCK(&(_ni)->ni_savedq);				\
+	(_qlen) = _IF_QLEN(&(_ni)->ni_savedq);			\
+	_IF_DRAIN(&(_ni)->ni_savedq);				\
+	IF_UNLOCK(&(_ni)->ni_savedq);				\
+} while (0)
+
+/*
  * 802.1x MAC ACL database locking definitions.
  */
 typedef struct mtx acl_lock_t;

==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#16 (text+ko) ====

@@ -230,26 +230,36 @@
 		ni->ni_rssi = rssi;
 		ni->ni_rstamp = rstamp;
 		if (HAS_SEQ(type)) {
+			u_int8_t tid;
+			if (IEEE80211_QOS_HAS_SEQ(wh)) {
+				tid = ((struct ieee80211_qosframe *)wh)->
+					i_qos[0] & IEEE80211_QOS_TID;
+				if (tid >= WME_AC_VI)
+					ic->ic_wme.wme_hipri_traffic++;
+				tid++;
+			} else
+				tid = 0;
 			rxseq = le16toh(*(u_int16_t *)wh->i_seq);
-			/* NB: QoS frames are handled separately below */
 			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    (type != IEEE80211_FC0_TYPE_DATA ||
-			     (subtype & IEEE80211_FC0_SUBTYPE_QOS) == 0) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseq)) {
+			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
 				/* duplicate, discard */
 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
-					"[%s] discard duplicate frame, "
-					"seqno <%u,%u> fragno <%u,%u>\n",
-					ether_sprintf(bssid),
-					rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
-					ni->ni_rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
-					rxseq & IEEE80211_SEQ_FRAG_MASK,
-					ni->ni_rxseq & IEEE80211_SEQ_FRAG_MASK);
+				    "[%s] discard duplicate frame, "
+				    "seqno <%u,%u> fragno <%u,%u> tid %u\n"
+				    , ether_sprintf(bssid)
+				    , rxseq >> IEEE80211_SEQ_SEQ_SHIFT
+				    , ni->ni_rxseqs[tid] >>
+					IEEE80211_SEQ_SEQ_SHIFT
+				    , rxseq & IEEE80211_SEQ_FRAG_MASK
+				    , ni->ni_rxseqs[tid] &
+					IEEE80211_SEQ_FRAG_MASK
+				    , tid
+				);
 				ic->ic_stats.is_rx_dup++;
 				IEEE80211_NODE_STAT(ni, rx_dup);
 				goto out;
 			}
-			ni->ni_rxseq = rxseq;
+			ni->ni_rxseqs[tid] = rxseq;
 		}
 	}
 
@@ -258,7 +268,8 @@
 		hdrsize = ieee80211_hdrsize(wh);
 		if (ic->ic_flags & IEEE80211_F_DATAPAD)
 			hdrsize = roundup(hdrsize, sizeof(u_int32_t));
-		if (m->m_pkthdr.len < hdrsize) {
+		if (m->m_len < hdrsize &&
+		    (m = m_pullup(m, hdrsize)) == NULL) {
 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
 			    "[%s] data frame too short, len %u, expecting %u\n",
 			    ether_sprintf(ieee80211_getbssid(ic, wh)),
@@ -267,38 +278,15 @@
 			goto out;		/* XXX */
 		}
 		if (subtype & IEEE80211_FC0_SUBTYPE_QOS) {
-			u_int8_t tid;
-
 			/* XXX discard if node w/o IEEE80211_NODE_QOS? */
 			/*
-			 * Check per-tid rx sequence counter for retries.
-			 */
-			tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] & 0xf;
-			rxseq = le16toh(*(u_int16_t *)wh->i_seq);
-			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
-				/* duplicate, discard */
-				IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT,
-				    "[%s] discard duplicate QoS frame,"
-				    " seqno <%u,%u> fragno <%u,%u>\n",
-				    ether_sprintf(ieee80211_getbssid(ic, wh)),
-				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
-				    ni->ni_rxseqs[tid] >> IEEE80211_SEQ_SEQ_SHIFT,
-				    rxseq & IEEE80211_SEQ_FRAG_MASK,
-				    ni->ni_rxseqs[tid] & IEEE80211_SEQ_FRAG_MASK);
-				ic->ic_stats.is_rx_dup++;
-				IEEE80211_NODE_STAT(ni, rx_dup);
-				goto out;
-			}
-			ni->ni_rxseqs[tid] = rxseq;
-			/*
-			 * Strip QoS header and any padding so only a
+			 * Strip QoS control and any padding so only a
 			 * stock 802.11 header is at the front.
 			 */
 			/* XXX 4-address QoS frame */
 			off = hdrsize - sizeof(struct ieee80211_frame);
 			ovbcopy(mtod(m, u_int8_t *), mtod(m, u_int8_t *) + off,
-				sizeof(struct ieee80211_frame));
+				hdrsize - off);
 			m_adj(m, off);
 			wh = mtod(m, struct ieee80211_frame *);
 			wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
@@ -715,8 +703,8 @@
 static struct mbuf *
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m)
 {
+	struct ieee80211_frame wh;	/* NB: QoS stripped above */
 	struct ether_header *eh;
-	struct ieee80211_frame wh;
 	struct llc *llc;
 
 	if (m->m_len < sizeof(wh) + sizeof(*llc) &&
@@ -1228,6 +1216,20 @@
 }
 
 static int __inline
+iswmeparam(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_PARAM_OUI_SUBTYPE;
+}
+
+static int __inline
+iswmeinfo(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_INFO_OUI_SUBTYPE;
+}
+
+static int __inline
 isatherosoui(const u_int8_t *frm)
 {
 	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
@@ -1541,6 +1543,41 @@
 	return 0;
 }
 
+static int
+ieee80211_parse_wmeparams(struct ieee80211com *ic, u_int8_t *frm)
+{
+#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
+	struct ieee80211_wme_state *wme = &ic->ic_wme;
+	u_int len = frm[1], qosinfo;
+	int i;
+
+	if (len < sizeof(struct ieee80211_wme_param)) {
+		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
+			"%s: length %u too short\n", __func__, len);
+		return 0;
+	}
+	qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
+	if ((qosinfo & WME_QOSINFO_COUNT) < wme->wme_wmeChanParams.cap_info) {
+		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
+			"%s: count mismatch, qosinfo 0x%x expected 0x%x\n",
+			__func__, qosinfo, wme->wme_wmeChanParams.cap_info);
+		return 0;
+	}
+	frm += __offsetof(struct ieee80211_wme_param, params_acParams);
+	for (i = 0; i < WME_NUM_AC; i++) {
+		struct wmeParams *wmep = &wme->wme_chanParams.cap_wmeParams[i];
+		/* NB: ACI not used */
+		wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM);
+		wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN);
+		wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN);
+		wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX);
+		wmep->wmep_txopLimit = LE_READ_2(frm+2);
+		frm += 4;
+	}
+	return 1;
+#undef MS
+}
+
 static void
 ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie)
 {
@@ -1713,7 +1750,7 @@
 			case IEEE80211_ELEMID_VENDOR:
 				if (iswpaoui(frm))
 					wpa = frm;
-				else if (iswmeoui(frm))
+				else if (iswmeparam(frm) || iswmeinfo(frm))
 					wme = frm;
 				/* XXX Atheros OUI support */
 				break;
@@ -1764,8 +1801,7 @@
 		/*
 		 * When operating in station mode, check for state updates.
 		 * Be careful to ignore beacons received while doing a
-		 * background scan.  We consider only 11g stuff right now
-		 * (XXX WME to come).
+		 * background scan.  We consider only 11g/WMM stuff right now.
 		 */
 		if (ni->ni_associd != 0 &&
 		    ((ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
@@ -1800,6 +1836,8 @@
 				ni->ni_capinfo = capinfo;
 				/* XXX statistic */
 			}
+			if (wme != NULL && ieee80211_parse_wmeparams(ic, wme))
+				ieee80211_wme_updateparams(ic);
 			ni->ni_inact = ic->ic_inact_run;
 			/* NB: don't need the rest of this */
 			return;
@@ -2081,7 +2119,7 @@
 				if (iswpaoui(frm)) {
 					if (ic->ic_flags & IEEE80211_F_WPA1)
 						wpa = frm;
-				} else if (iswmeoui(frm))
+				} else if (iswmeinfo(frm))
 					wme = frm;
 				/* XXX Atheros OUI support */
 				break;
@@ -2205,7 +2243,7 @@
 			 * as capable of QoS and record information
 			 * element for applications that require it.
 			 */
-			ieee80211_saveie(&ni->ni_wpa_ie, wpa);
+			ieee80211_saveie(&ni->ni_wme_ie, wme);
 			ni->ni_flags |= IEEE80211_NODE_QOS;
 		} else if (ni->ni_wme_ie != NULL) {
 			/*
@@ -2294,9 +2332,10 @@
 
 		ni->ni_capinfo = capinfo;
 		ni->ni_associd = associd;
-		if (wme != NULL)
+		if (wme != NULL && ieee80211_parse_wmeparams(ic, wme)) {
 			ni->ni_flags |= IEEE80211_NODE_QOS;
-		else
+			ieee80211_wme_updateparams(ic);
+		} else
 			ni->ni_flags &= ~IEEE80211_NODE_QOS;
 		/*
 		 * Configure state now that we are associated.
@@ -2455,15 +2494,17 @@
 	/*
 	 * Flush queued unicast frames.
 	 */
-	if (_IF_QLEN(&ni->ni_savedq) == 0) {
+	if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) {
 		ic->ic_set_tim(ic, ni, 0);	/* just in case */
 		return;
 	}
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
 	    "[%s] flush ps queue, %u packets queued\n",
-	    ether_sprintf(ni->ni_macaddr), _IF_QLEN(&ni->ni_savedq));
+	    ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_SAVEQ_QLEN(ni));
 	for (;;) {
-		_IF_DEQUEUE(&ni->ni_savedq, m);
+		int qlen;
+
+		IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
 		if (m == NULL)
 			break;
 		/* 
@@ -2471,12 +2512,13 @@
 		 * If there are more packets, set the more packets bit
 		 * in the packet dispatched to the station.
 		 */
-		if (_IF_QLEN(&ni->ni_savedq) != 0) {
+		if (qlen != 0) {
 			struct ieee80211_frame_min *wh =
 				mtod(m, struct ieee80211_frame_min *);
 			wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
 		}
 		/* XXX need different driver interface */
+		/* XXX bypasses q max */
 		IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
 	}
 }
@@ -2491,6 +2533,7 @@
 	struct ieee80211_frame_min *wh;
 	struct mbuf *m;
 	u_int16_t aid;
+	int qlen;
 
 	wh = mtod(m0, struct ieee80211_frame_min *);
 	if (ni->ni_associd == 0) {
@@ -2516,7 +2559,7 @@
 	ni->ni_inact = ic->ic_inact_run;
 
 	/* Okay, take the first queued packet and put it out... */
-	_IF_DEQUEUE(&ni->ni_savedq, m);
+	IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
 	if (m == NULL) {
 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
 			"[%s] got ps-poll, but queue empty\n",
@@ -2533,8 +2576,8 @@
 	 */
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
 		"[%s] got ps-poll, send packet, %u still queued\n",
-		ether_sprintf(ni->ni_macaddr), _IF_QLEN(&ni->ni_savedq));
-	if (_IF_QLEN(&ni->ni_savedq) != 0) {
+		ether_sprintf(ni->ni_macaddr), qlen);
+	if (qlen != 0) {
 		wh = mtod(m, struct ieee80211_frame_min *);
 		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
 	} else

==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#17 (text+ko) ====

@@ -1056,9 +1056,13 @@
 	si->isi_associd = ni->ni_associd;
 	si->isi_txpower = ni->ni_txpower;
 	si->isi_vlan = ni->ni_vlan;
-	si->isi_txseq = ni->ni_txseq;
-	si->isi_rxseq = ni->ni_rxseq;
-	memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
+	if (ni->ni_flags & IEEE80211_NODE_QOS) {
+		memcpy(si->isi_txseqs, ni->ni_txseqs, sizeof(ni->ni_txseqs));
+		memcpy(si->isi_rxseqs, ni->ni_rxseqs, sizeof(ni->ni_rxseqs));
+	} else {
+		si->isi_txseqs[0] = ni->ni_txseqs[0];
+		si->isi_rxseqs[0] = ni->ni_rxseqs[0];
+	}
 	if (ic->ic_opmode == IEEE80211_M_IBSS || ni->ni_associd != 0)
 		si->isi_inact = ic->ic_inact_run;
 	else if (ieee80211_node_is_authorized(ni))
@@ -1137,6 +1141,46 @@
 }
 
 static int
+ieee80211_ioctl_getwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
+{
+	struct ieee80211_wme_state *wme = &ic->ic_wme;
+	struct wmeParams *wmep;
+	int ac;
+
+	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
+		return EINVAL;
+
+	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
+	if (ac >= WME_NUM_AC)
+		ac = WME_AC_BE;
+	if (ireq->i_len & IEEE80211_WMEPARAM_BSS)
+		wmep = &wme->wme_bssChanParams.cap_wmeParams[ac];
+	else
+		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
+	switch (ireq->i_type) {
+	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
+		ireq->i_val = wmep->wmep_logcwmin;
+		break;
+	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
+		ireq->i_val = wmep->wmep_logcwmax;
+		break;
+	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
+		ireq->i_val = wmep->wmep_aifsn;
+		break;
+	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
+		ireq->i_val = wmep->wmep_txopLimit;
+		break;
+	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
+		ireq->i_val = wmep->wmep_acm;
+		break;
+	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
+		ireq->i_val = wmep->wmep_noackPolicy;
+		break;
+	}
+	return 0;
+}
+
+static int
 ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
 {
 	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
@@ -1326,6 +1370,14 @@
 	case IEEE80211_IOC_STA_INFO:
 		error = ieee80211_ioctl_getstainfo(ic, ireq);
 		break;
+	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
+	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
+	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
+	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
+	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
+	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
+		error = ieee80211_ioctl_getwmeparam(ic, ireq);
+		break;
 	default:
 		error = EINVAL;
 		break;
@@ -1650,6 +1702,81 @@
 }
 
 static int
+ieee80211_ioctl_setwmeparam(struct ieee80211com *ic, struct ieee80211req *ireq)
+{
+	struct ieee80211_wme_state *wme = &ic->ic_wme;
+	struct wmeParams *wmep, *chanp;
+	int isbss, ac;
+
+	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
+		return EINVAL;
+
+	isbss = (ireq->i_len & IEEE80211_WMEPARAM_BSS);
+	ac = (ireq->i_len & IEEE80211_WMEPARAM_VAL);
+	if (ac >= WME_NUM_AC)
+		ac = WME_AC_BE;
+	if (isbss) {
+		chanp = &wme->wme_bssChanParams.cap_wmeParams[ac];
+		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[ac];
+	} else {
+		chanp = &wme->wme_chanParams.cap_wmeParams[ac];
+		wmep = &wme->wme_wmeChanParams.cap_wmeParams[ac];
+	}
+	switch (ireq->i_type) {
+	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
+		if (isbss) {
+			wmep->wmep_logcwmin = ireq->i_val;
+			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
+				chanp->wmep_logcwmin = ireq->i_val;
+		} else {
+			wmep->wmep_logcwmin = chanp->wmep_logcwmin =
+				ireq->i_val;
+		}
+		break;
+	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
+		if (isbss) {
+			wmep->wmep_logcwmax = ireq->i_val;
+			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
+				chanp->wmep_logcwmax = ireq->i_val;
+		} else {
+			wmep->wmep_logcwmax = chanp->wmep_logcwmax =
+				ireq->i_val;
+		}
+		break;
+	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
+		if (isbss) {
+			wmep->wmep_aifsn = ireq->i_val;
+			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
+				chanp->wmep_aifsn = ireq->i_val;
+		} else {
+			wmep->wmep_aifsn = chanp->wmep_aifsn = ireq->i_val;
+		}
+		break;
+	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
+		if (isbss) {
+			wmep->wmep_txopLimit = ireq->i_val;
+			if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
+				chanp->wmep_txopLimit = ireq->i_val;
+		} else {
+			wmep->wmep_txopLimit = chanp->wmep_txopLimit =
+				ireq->i_val;
+		}
+		break;
+	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
+		wmep->wmep_acm = ireq->i_val;
+		if ((wme->wme_flags & WME_F_AGGRMODE) == 0)
+			chanp->wmep_acm = ireq->i_val;
+		break;
+	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (!bss only)*/
+		wmep->wmep_noackPolicy = chanp->wmep_noackPolicy =
+			(ireq->i_val) != 0;
+		break;
+	}
+	ieee80211_wme_updateparams(ic);
+	return 0;
+}
+
+static int
 cipher2cap(int cipher)
 {
 	switch (cipher) {
@@ -1923,12 +2050,13 @@
 		error = ENETRESET;		/* XXX? */
 		break;
 	case IEEE80211_IOC_WME:
-		if (ic->ic_opmode != IEEE80211_M_STA)
-			return EINVAL;
-		if (ireq->i_val)
+		if (ireq->i_val) {
+			if ((ic->ic_caps & IEEE80211_C_WME) == 0)
+				return EINVAL;
 			ic->ic_flags |= IEEE80211_F_WME;
-		else
+		} else
 			ic->ic_flags &= ~IEEE80211_F_WME;
+		error = ENETRESET;		/* XXX maybe not for station? */
 		break;
 	case IEEE80211_IOC_HIDESSID:
 		if (ireq->i_val)
@@ -2033,6 +2161,14 @@
 	case IEEE80211_IOC_STA_TXPOW:
 		error = ieee80211_ioctl_setstatxpow(ic, ireq);
 		break;
+	case IEEE80211_IOC_WME_CWMIN:		/* WME: CWmin */
+	case IEEE80211_IOC_WME_CWMAX:		/* WME: CWmax */
+	case IEEE80211_IOC_WME_AIFS:		/* WME: AIFS */
+	case IEEE80211_IOC_WME_TXOPLIMIT:	/* WME: txops limit */
+	case IEEE80211_IOC_WME_ACM:		/* WME: ACM (bss only) */
+	case IEEE80211_IOC_WME_ACKPOLICY:	/* WME: ACK policy (bss only) */
+		error = ieee80211_ioctl_setwmeparam(ic, ireq);
+		break;
 	default:
 		error = EINVAL;
 		break;

==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#11 (text+ko) ====

@@ -296,13 +296,12 @@
 						/* negotiated rates */
 	u_int8_t	isi_rates[IEEE80211_RATE_MAXSIZE];
 	u_int8_t	isi_txrate;		/* index to isi_rates[] */
-	u_int8_t	isi_ie_len;		/* IE length */
+	u_int16_t	isi_ie_len;		/* IE length */
 	u_int16_t	isi_associd;		/* assoc response */
 	u_int16_t	isi_txpower;		/* current tx power */
 	u_int16_t	isi_vlan;		/* vlan tag */
-	u_int16_t	isi_txseq;		/* seq to be transmitted */
-	u_int16_t	isi_rxseq;		/* seq previous received */
-	u_int16_t	isi_rxseqs[16];		/* seq previous for qos frames*/
+	u_int16_t	isi_txseqs[17];		/* seq to be transmitted */
+	u_int16_t	isi_rxseqs[17];		/* seq previous for qos frames*/
 	u_int16_t	isi_inact;		/* inactivity timer */
 	/* XXX frag state? */
 	/* variable length IE data */
@@ -329,6 +328,16 @@
 	u_int8_t	it_txpow;
 };
 
+/*
+ * WME parameters are set and return using i_val and i_len.
+ * i_val holds the value itself.  i_len specifies the AC
+ * and, as appropriate, then high bit specifies whether the
+ * operation is to be applied to the BSS or ourself.
+ */
+#define	IEEE80211_WMEPARAM_SELF	0x0000		/* parameter applies to self */
+#define	IEEE80211_WMEPARAM_BSS	0x8000		/* parameter applies to BSS */
+#define	IEEE80211_WMEPARAM_VAL	0x7fff		/* parameter value */
+
 #ifdef __FreeBSD__
 /*
  * FreeBSD-style ioctls.
@@ -402,6 +411,12 @@
 #define	IEEE80211_IOC_TXPOWMAX		43	/* max tx power for channel */
 #define	IEEE80211_IOC_STA_TXPOW		44	/* per-station tx power limit */
 #define	IEEE80211_IOC_STA_INFO		45	/* station/neighbor info */
+#define	IEEE80211_IOC_WME_CWMIN		46	/* WME: CWmin */
+#define	IEEE80211_IOC_WME_CWMAX		47	/* WME: CWmax */
+#define	IEEE80211_IOC_WME_AIFS		48	/* WME: AIFS */
+#define	IEEE80211_IOC_WME_TXOPLIMIT	49	/* WME: txops limit */
+#define	IEEE80211_IOC_WME_ACM		50	/* WME: ACM (bss only) */
+#define	IEEE80211_IOC_WME_ACKPOLICY	51	/* WME: ACK policy (!bss only)*/
 
 /*
  * Scan result data returned for IEEE80211_IOC_SCAN_RESULTS.

==== //depot/projects/wifi/sys/net80211/ieee80211_node.c#18 (text+ko) ====

@@ -427,6 +427,7 @@
 	 * mode is locked.
 	 */ 
 	ieee80211_reset_erp(ic);
+	ieee80211_wme_initparams(ic);
 
 	ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 }
@@ -766,6 +767,7 @@
 	 */ 
 	ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan);
 	ieee80211_reset_erp(ic);
+	ieee80211_wme_initparams(ic);
 	if (ic->ic_opmode == IEEE80211_M_IBSS)
 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 	else
@@ -805,7 +807,7 @@
 {
 #define	N(a)	(sizeof(a)/sizeof(a[0]))
 	struct ieee80211com *ic = ni->ni_ic;
-	int i;
+	int i, qlen;
 
 	/* NB: preserve ni_table */
 	if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) {
@@ -815,14 +817,14 @@
 		    "[%s] power save mode off, %u sta's in ps mode\n",
 		    ether_sprintf(ni->ni_macaddr), ic->ic_ps_sta);
 	}
-	if (_IF_QLEN(&ni->ni_savedq) != 0) {
-		/*
-		 * Drain power save queue.
-		 */
-		_IF_DRAIN(&ni->ni_savedq);
-		if (ic->ic_set_tim != NULL)
-			ic->ic_set_tim(ic, ni, 0);
-	}
+
+	/*
+	 * Drain power save queue and, if needed, clear TIM.
+	 */
+	IEEE80211_NODE_SAVEQ_DRAIN(ni, qlen);
+	if (qlen != 0 && ic->ic_set_tim != NULL)
+		ic->ic_set_tim(ic, ni, 0);
+
 	ni->ni_associd = 0;
 	if (ni->ni_challenge != NULL) {
 		FREE(ni->ni_challenge, M_DEVBUF);
@@ -859,6 +861,7 @@
 		FREE(ni->ni_wpa_ie, M_DEVBUF);
 	if (ni->ni_wme_ie != NULL)
 		FREE(ni->ni_wme_ie, M_DEVBUF);
+	IEEE80211_NODE_SAVEQ_DESTROY(ni);
 	FREE(ni, M_80211_NODE);
 }
 
@@ -887,6 +890,7 @@
 	ni->ni_txpower = ic->ic_txpowlimit;	/* max power */
 	ieee80211_crypto_resetkey(ic, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE);
 	ni->ni_inact = nt->nt_inact_init;
+	IEEE80211_NODE_SAVEQ_INIT(ni, "unknown");
 
 	IEEE80211_NODE_LOCK(nt);
 	TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
@@ -1395,9 +1399,9 @@
 	printf("\tassocid 0x%x txpower %u vlan %u\n",
 		ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
 	printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
-		ni->ni_txseq,
-		ni->ni_rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
-		ni->ni_rxseq & IEEE80211_SEQ_FRAG_MASK,
+		ni->ni_txseqs[0],
+		ni->ni_rxseqs[0] >> IEEE80211_SEQ_SEQ_SHIFT,
+		ni->ni_rxseqs[0] & IEEE80211_SEQ_FRAG_MASK,
 		ni->ni_rxfragstamp);
 	printf("\trstamp %u rssi %u intval %u capinfo 0x%x\n",
 		ni->ni_rstamp, ni->ni_rssi, ni->ni_intval, ni->ni_capinfo);
@@ -1500,6 +1504,7 @@
 		}
 		ni->ni_associd = aid | 0xc000;
 		IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
+		ic->ic_sta_assoc++;
 		newassoc = 1;
 		if (ic->ic_curmode == IEEE80211_MODE_11G)
 			ieee80211_node_join_11g(ic, ni);
@@ -1615,6 +1620,7 @@
 		ic->ic_auth->ia_node_leave(ic, ni);
 	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
 	ni->ni_associd = 0;
+	ic->ic_sta_assoc--;
 
 	if (ic->ic_curmode == IEEE80211_MODE_11G)
 		ieee80211_node_leave_11g(ic, ni);
@@ -1700,7 +1706,7 @@
 	KASSERT(aid < ic->ic_max_aid,
 		("bogus aid %u, max %u", aid, ic->ic_max_aid));
 
-	/* XXX locking */
+	IEEE80211_BEACON_LOCK(ic);
 	if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) {
 		if (set) {
 			setbit(ic->ic_tim_bitmap, aid);
@@ -1714,6 +1720,7 @@
 			ether_sprintf(ni->ni_macaddr), aid, set ? "" : "no ");
 		ic->ic_flags |= IEEE80211_F_TIMUPDATE;
 	}
+	IEEE80211_BEACON_UNLOCK(ic);
 }
 
 /*

==== //depot/projects/wifi/sys/net80211/ieee80211_node.h#11 (text+ko) ====

@@ -105,9 +105,8 @@
 	u_int32_t		*ni_challenge;	/* shared-key challenge */
 	u_int8_t		*ni_wpa_ie;	/* captured WPA/RSN ie */
 	u_int8_t		*ni_wme_ie;	/* captured WME ie */
-	u_int16_t		ni_txseq;	/* seq to be transmitted */
-	u_int16_t		ni_rxseq;	/* seq previous received */
-	u_int16_t		ni_rxseqs[16];	/* seq previous for qos frames*/
+	u_int16_t		ni_txseqs[17];	/* tx seq per-tid */
+	u_int16_t		ni_rxseqs[17];	/* rx seq previous per-tid*/
 	u_int32_t		ni_rxfragstamp;	/* time stamp of last rx frag */
 	struct mbuf		*ni_rxfrag[3];	/* rx frag reassembly */
 	struct ieee80211_rsnparms ni_rsn;	/* RSN/WPA parameters */
@@ -141,17 +140,7 @@
 	int			ni_fails;	/* failure count to associate */
 	int			ni_inact;	/* inactivity mark count */
 	int			ni_txrate;	/* index to ni_rates[] */
-	/*
-	 * NB: this queue is manipulated without explicit locking,
-	 * so always use the _ variant macros.  We might be better
-	 * off just rolling our own packet queue to avoid these
-	 * shenanigans.
-	 */
-#if 1
-	struct	ifaltq		ni_savedq;	/* ps-poll queue */
-#else
 	struct	ifqueue		ni_savedq;	/* ps-poll queue */
-#endif
 	struct ieee80211_nodestats ni_stats;	/* per-node statistics */
 };
 MALLOC_DECLARE(M_80211_NODE);

==== //depot/projects/wifi/sys/net80211/ieee80211_output.c#10 (text+ko) ====

@@ -117,8 +117,8 @@
 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
 	*(u_int16_t *)wh->i_dur = 0;
 	*(u_int16_t *)wh->i_seq =
-	    htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
-	ni->ni_txseq++;
+	    htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
+	ni->ni_txseqs[0]++;
 	/*
 	 * Hack.  When sending PROBE_REQ frames while scanning we
 	 * explicitly force a broadcast rather than (as before) clobber
@@ -186,8 +186,8 @@
 		IEEE80211_FC0_SUBTYPE_NODATA;
 	*(u_int16_t *)wh->i_dur = 0;
 	*(u_int16_t *)wh->i_seq =
-	    htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
-	ni->ni_txseq++;
+	    htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
+	ni->ni_txseqs[0]++;
 
 	/* XXX WDS */
 	wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
@@ -272,6 +272,122 @@
 #undef TO_BE_RECLAIMED
 }
 
+/* 
+ * Assign priority to a frame based on any vlan tag assigned
+ * to the station and/or any Diffserv setting in an IP header.
+ * Finally, if an ACM policy is setup (in station mode) it's
+ * applied.
+ */
+int
+ieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni)
+{
+	int v_wme_ac, d_wme_ac, ac;
+#ifdef INET
+	struct ether_header *eh;
+#endif
+
+	if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) {
+		ac = WME_AC_BE;
+		goto done;
+	}
+
+	/* 
+	 * If node has a vlan tag then all traffic
+	 * to it must have a matching tag.
+	 */
+	v_wme_ac = 0;
+	if (ni->ni_vlan != 0) {
+		 struct m_tag *mtag = VLAN_OUTPUT_TAG(ic->ic_ifp, m);
+		 if (mtag != NULL) {
+			IEEE80211_NODE_STAT(ni, tx_novlantag);
+			return 1;
+		}
+		if (EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)) !=
+		    EVL_VLANOFTAG(ni->ni_vlan)) {
+			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
+			return 1;
+		}
+		/* map vlan priority to AC */
+		switch (EVL_PRIOFTAG(ni->ni_vlan)) {
+		case 1:
+		case 2:
+			v_wme_ac = WME_AC_BK;
+			break;
+		case 0:
+		case 3:
+			v_wme_ac = WME_AC_BE;
+			break;
+		case 4:
+		case 5:
+			v_wme_ac = WME_AC_VI;
+			break;
+		case 6:
+		case 7:
+			v_wme_ac = WME_AC_VO;
+			break;
+		}
+	}

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list