Date: Tue, 23 Nov 2004 03:54:53 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 65686 for review Message-ID: <200411230354.iAN3srGl002384@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=65686 Change 65686 by sam@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) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200411230354.iAN3srGl002384>