summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-06-21 18:20:19 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-06-21 18:20:19 +0000
commitec3a5f87d047f0e6852888f3fc4515c5a6ea9144 (patch)
treeeef05c80d49c6b3bce47dc600c9690f6d077d219 /sys
parent13c0452df08515a434dba5dd14a9a1d64e12d1f9 (diff)
add code to parse EDCA parameter set information elements.
add myself to the copyright list.
Diffstat (limited to 'sys')
-rw-r--r--sys/net80211/ieee80211_input.c121
1 files changed, 116 insertions, 5 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 7b581298967..e1db18ac442 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,8 +1,9 @@
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
-/* $OpenBSD: ieee80211_input.c,v 1.28 2007/06/21 16:15:29 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.29 2007/06/21 18:20:18 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007 Damien Bergamini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -68,6 +69,10 @@ int ieee80211_setup_rates(struct ieee80211com *, struct ieee80211_node *,
void ieee80211_auth_open(struct ieee80211com *,
const struct ieee80211_frame *, struct ieee80211_node *, int,
u_int32_t, u_int16_t, u_int16_t);
+int ieee80211_parse_edca_params_common(struct ieee80211com *,
+ const u_int8_t *);
+int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
+int ieee80211_parse_wmm_params(struct ieee80211com *, const u_int8_t *);
void ieee80211_recv_pspoll(struct ieee80211com *, struct mbuf *, int,
u_int32_t);
int ieee80211_do_slow_print(struct ieee80211com *, int *);
@@ -926,6 +931,87 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
}
#endif
+/* unaligned little endian access */
+#define LE_READ_2(p) \
+ ((u_int16_t) \
+ ((((const u_int8_t *)(p))[0]) | \
+ (((const u_int8_t *)(p))[1] << 8)))
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0]) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+int
+ieee80211_parse_edca_params_common(struct ieee80211com *ic,
+ const u_int8_t *frm)
+{
+ u_int updtcount;
+ int aci;
+
+ /*
+ * Check if EDCA parameters have changed XXX if we miss more than
+ * 15 consecutive beacons, we might not detect changes to EDCA
+ * parameters due to wraparound of the 4-bit Update Count field.
+ */
+ updtcount = frm[0] & 0xf;
+ if (updtcount == ic->ic_edca_updtcount)
+ return 0; /* no changes to EDCA parameters, ignore */
+ ic->ic_edca_updtcount = updtcount;
+
+ frm += 2; /* skip QoS Info + Reserved fields */
+
+ /* parse AC Parameter Records */
+ for (aci = 0; aci < EDCA_NUM_AC; aci++) {
+ struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[aci];
+
+ ac->ac_acm = (frm[0] >> 4) & 0x1;
+ ac->ac_aifsn = frm[0] & 0xf;
+ ac->ac_ecwmin = frm[1] & 0xf;
+ ac->ac_ecwmax = frm[1] >> 4;
+ ac->ac_txoplimit = LE_READ_2(frm + 2);
+ frm += 4;
+ }
+ /* give drivers a chance to update their settings */
+ if ((ic->ic_flags & IEEE80211_F_QOS) && ic->ic_updateedca != NULL)
+ (*ic->ic_updateedca)(ic);
+
+ return 0;
+}
+
+int
+ieee80211_parse_edca_params(struct ieee80211com *ic, const u_int8_t *frm)
+{
+ /* check IE length */
+ if (frm[1] < 18) {
+ IEEE80211_DPRINTF(("%s: invalid EDCA parameter set IE;"
+ " length %u, expecting 18\n", __func__, frm[1]));
+ ic->ic_stats.is_rx_elem_toosmall++;
+ return 1;
+ }
+ return ieee80211_parse_edca_params_common(ic, frm + 2);
+}
+
+/*
+ * And now comes the Wi-Fi Alliance WMM compatibility mess.
+ * Most APs that advertise themselves as being 802.11e-compatible still
+ * continue to use the vendor-specific IE instead of the one defined in
+ * the IEEE standard.
+ */
+int
+ieee80211_parse_wmm_params(struct ieee80211com *ic, const u_int8_t *frm)
+{
+ /* check IE length */
+ if (frm[1] < 24) {
+ IEEE80211_DPRINTF(("%s: invalid WMM parameter set IE;"
+ " length %u, expecting 24\n", __func__, frm[1]));
+ ic->ic_stats.is_rx_elem_toosmall++;
+ return 1;
+ }
+ return ieee80211_parse_edca_params_common(ic, frm + 8);
+}
+
/*-
* Beacon/Probe response frame format:
* [8] Timestamp
@@ -938,6 +1024,8 @@ ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
* [tlv*] DS Parameter Set (802.11g)
* [tlv] ERP Information (802.11g)
* [tlv] Extended Supported Rates (802.11g)
+ * [tlv] EDCA Parameter Set (802.11e)
+ * [tlv] QoS Capability (Beacon only, 802.11e)
*/
void
ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
@@ -948,7 +1036,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
- const u_int8_t *ssid, *rates, *xrates;
+ const u_int8_t *ssid, *rates, *xrates, *edca;
const u_int8_t *tstamp, *bintval, *capinfo, *country;
u_int8_t chan, bchan, fhindex, erp;
u_int16_t fhdwell;
@@ -982,7 +1070,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
tstamp = frm; frm += 8;
bintval = frm; frm += 2;
capinfo = frm; frm += 2;
- ssid = rates = xrates = country = NULL;
+ ssid = rates = xrates = country = edca = NULL;
bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
chan = bchan;
fhdwell = 0;
@@ -1031,6 +1119,11 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
}
erp = frm[2];
break;
+ case IEEE80211_ELEMID_EDCAPARMS:
+ edca = frm;
+ break;
+ case IEEE80211_ELEMID_QOS_CAP:
+ break;
default:
IEEE80211_DPRINTF2(("%s: element id %u/len %u "
"ignored\n", __func__, *frm, frm[1]));
@@ -1150,6 +1243,8 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
IEEE80211_CAPINFO_SHORT_SLOTTIME));
}
}
+ if (edca != NULL && (ni->ni_flags & IEEE80211_NODE_QOS))
+ ieee80211_parse_edca_params(ic, edca);
if (ssid[1] != 0 && ni->ni_esslen == 0) {
/*
@@ -1317,6 +1412,7 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0,
* [tlv] SSID
* [tlv] Supported rates
* [tlv] Extended Supported Rates (802.11g)
+ * [tlv] QoS Capability (802.11e)
*/
void
ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
@@ -1370,6 +1466,8 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_ELEMID_XRATES:
xrates = frm;
break;
+ case IEEE80211_ELEMID_QOS_CAP:
+ break;
}
frm += frm[1] + 2;
}
@@ -1445,6 +1543,7 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
* [2] Association ID (AID)
* [tlv] Supported rates
* [tlv] Extended Supported Rates (802.11g)
+ * [tlv] EDCA Parameter Set (802.11e)
*/
void
ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
@@ -1456,7 +1555,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
struct ifnet *ifp = &ic->ic_if;
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
- const u_int8_t *rates, *xrates;
+ const u_int8_t *rates, *xrates, *edca;
u_int16_t status;
if (ic->ic_opmode != IEEE80211_M_STA ||
@@ -1490,7 +1589,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
ni->ni_associd = letoh16(*(u_int16_t *)frm);
frm += 2;
- rates = xrates = NULL;
+ rates = xrates = edca = NULL;
while (frm < efrm) {
switch (*frm) {
case IEEE80211_ELEMID_RATES:
@@ -1499,6 +1598,9 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
case IEEE80211_ELEMID_XRATES:
xrates = frm;
break;
+ case IEEE80211_ELEMID_EDCAPARMS:
+ edca = frm;
+ break;
}
frm += frm[1] + 2;
}
@@ -1510,6 +1612,15 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0,
if (ni->ni_rates.rs_nrates == 0)
return;
+ if (edca != NULL) {
+ /* force update of EDCA parameters */
+ ic->ic_edca_updtcount = -1;
+
+ if (ieee80211_parse_edca_params(ic, edca) == 0)
+ ni->ni_flags |= IEEE80211_NODE_QOS;
+ else /* for Reassociation */
+ ni->ni_flags &= ~IEEE80211_NODE_QOS;
+ }
/*
* Configure state now that we are associated.
*/