diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2007-03-16 11:06:40 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2007-03-16 11:06:40 +0000 |
commit | e76012198cbc5b6c3283a9771ad74ea9cdc55873 (patch) | |
tree | f83f082cfd7bad3f2b97d8012d6804798b68677a /sys | |
parent | 18cfcaf08d56dbea951813cc108b1a4d48d41270 (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.c | 73 |
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 |