summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2007-03-16 11:06:40 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2007-03-16 11:06:40 +0000
commite76012198cbc5b6c3283a9771ad74ea9cdc55873 (patch)
treef83f082cfd7bad3f2b97d8012d6804798b68677a /sys
parent18cfcaf08d56dbea951813cc108b1a4d48d41270 (diff)
Split the beacon returned by ieee80211_beacon_alloc() in two parts and
fill everything up to IEEE80211_ELEMID_TIM into the beacon template and everything after and including IEEE80211_ELEMID_TIM into the tim template. This fixes the beacons on 11g where two TIM fields where announced. acx_beacon_locate() is used to calculate the offset to a defined TLV field. If other dirvers need it as well we may move it up into net80211. OK mglocker@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/acx.c73
1 files changed, 58 insertions, 15 deletions
diff --git a/sys/dev/ic/acx.c b/sys/dev/ic/acx.c
index d322f47f748..6fd387ebf6d 100644
--- a/sys/dev/ic/acx.c
+++ b/sys/dev/ic/acx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acx.c,v 1.67 2007/03/14 08:12:30 claudio Exp $ */
+/* $OpenBSD: acx.c,v 1.68 2007/03/16 11:06:39 claudio Exp $ */
/*
* Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
@@ -174,6 +174,7 @@ int acx_reset(struct acx_softc *);
int acx_set_null_tmplt(struct acx_softc *);
int acx_set_probe_req_tmplt(struct acx_softc *, const char *, int);
int acx_set_probe_resp_tmplt(struct acx_softc *, struct ieee80211_node *);
+int acx_beacon_locate(struct mbuf *, u_int8_t);
int acx_set_beacon_tmplt(struct acx_softc *, struct ieee80211_node *);
int acx_read_eeprom(struct acx_softc *, uint32_t, uint8_t *);
@@ -1830,15 +1831,6 @@ acx_init_tmplt_ordered(struct acx_softc *sc)
sizeof(data.presp)) != 0)
return (1);
- /* Setup TIM template */
- data.tim.tim_eid = IEEE80211_ELEMID_TIM;
- data.tim.tim_len = ACX_TIM_LEN(ACX_TIM_BITMAP_LEN);
- if (acx_set_tmplt(sc, ACXCMD_TMPLT_TIM, &data.tim,
- ACX_TMPLT_TIM_SIZ(ACX_TIM_BITMAP_LEN)) != 0) {
- printf("%s: can't set tim tmplt\n", sc->sc_dev.dv_xname);
- return (1);
- }
-
return (0);
}
@@ -2350,22 +2342,73 @@ acx_set_probe_resp_tmplt(struct acx_softc *sc, struct ieee80211_node *ni)
}
int
+acx_beacon_locate(struct mbuf *m, u_int8_t type)
+{
+ int off;
+ u_int8_t *frm;
+ /*
+ * beacon frame format
+ * [8] time stamp
+ * [2] beacon interval
+ * [2] cabability information
+ * from here on [tlv] values
+ */
+
+ if (m->m_len != m->m_pkthdr.len)
+ panic("beacon not in contiguous mbuf");
+
+ off = sizeof(struct ieee80211_frame) + 8 + 2 + 2;
+ frm = mtod(m, u_int8_t *);
+ for (; off + 1 < m->m_len; off += frm[off + 1] + 2) {
+ printf("acx_beacon_locate: off %d type %x len %x\n",
+ off, frm[off], frm[off + 1]);
+ if (frm[off] == type)
+ return (off);
+ }
+ /* type not found */
+ return (m->m_len);
+}
+
+int
acx_set_beacon_tmplt(struct acx_softc *sc, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
struct acx_tmplt_beacon beacon;
+ struct acx_tmplt_tim tim;
struct mbuf *m;
- int len;
+ int len, off;
+
+ bzero(&beacon, sizeof(beacon));
+ bzero(&tim, sizeof(tim));
m = ieee80211_beacon_alloc(ic, ni);
if (m == NULL)
return (1);
- bzero(&beacon, sizeof(beacon));
- m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&beacon.data);
- len = m->m_pkthdr.len + sizeof(beacon.size);
+
+ off = acx_beacon_locate(m, IEEE80211_ELEMID_TIM);
+ printf("acx_set_beacon_tmplt: acx_beacon_locate TIM off %d len %d\n",
+ off, m->m_pkthdr.len);
+
+ m_copydata(m, 0, off, (caddr_t)&beacon.data);
+ len = off + sizeof(beacon.size);
+
+ if (acx_set_tmplt(sc, ACXCMD_TMPLT_BEACON, &beacon, len) != 0) {
+ m_freem(m);
+ return (1);
+ }
+
+ len = m->m_pkthdr.len - off;
+ if (len == 0) {
+ /* no TIM field */
+ m_freem(m);
+ return (0);
+ }
+
+ m_copydata(m, off, len, (caddr_t)&tim.data);
+ len += sizeof(beacon.size);
m_freem(m);
- return (acx_set_tmplt(sc, ACXCMD_TMPLT_BEACON, &beacon, len));
+ return (acx_set_tmplt(sc, ACXCMD_TMPLT_TIM, &tim, len));
}
void