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