summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2004-12-31 20:32:40 +0000
committersam <sam@FreeBSD.org>2004-12-31 20:32:40 +0000
commit341ffa612f66fc3213f4bedb7d13a5ccf12b7490 (patch)
treec263ca48d3f51731ab7dc189eb0251af3193d035 /sys/dev/ath
parent186275ec87e54f7c5c3e4ec75fbcb167bee25fcc (diff)
downloadFreeBSD-src-341ffa612f66fc3213f4bedb7d13a5ccf12b7490.zip
FreeBSD-src-341ffa612f66fc3213f4bedb7d13a5ccf12b7490.tar.gz
Radiotap fixups:
o catch one place where we were not using ath_chan_change to switch channels; this fixes a problem where the channel settings were not being correctly reported in captured packets o return unique channel identification in the channel flags; ethereal gets confused if you return merged flags (e.g. ofdm, cck, and 2Ghz) (this is workaround and should be removed if we can ever cleanup radiotap consumers) o correct short/long preamble flag state for rx and treat tx the same--use a new hwflags array that gives us the data based on the h/w rate index/cookie o add gross hack to handle radiotap capture of frames that come in with hardware padding; should be replaced by a flag in the radiotap header and more smarts in the apps that decode radiotap data
Diffstat (limited to 'sys/dev/ath')
-rw-r--r--sys/dev/ath/if_ath.c78
-rw-r--r--sys/dev/ath/if_athvar.h12
2 files changed, 69 insertions, 21 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index a46e8c6..3f436c6 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -821,7 +821,6 @@ ath_init(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &sc->sc_if;
struct ieee80211_node *ni;
- enum ieee80211_phymode mode;
struct ath_hal *ah = sc->sc_ah;
HAL_STATUS status;
@@ -893,9 +892,7 @@ ath_init(void *arg)
*/
ni = ic->ic_bss;
ni->ni_chan = ic->ic_ibss_chan;
- mode = ieee80211_chan2mode(ic, ni->ni_chan);
- if (mode != sc->sc_curmode)
- ath_setcurmode(sc, mode);
+ ath_chan_change(sc, ni->ni_chan);
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
@@ -2614,6 +2611,10 @@ rx_accept:
sc->sc_stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++;
if (sc->sc_drvbpf) {
+ const void *data;
+ int hdrsize, hdrspace;
+ u_int8_t rix;
+
/*
* Discard anything shorter than an ack or cts.
*/
@@ -2625,14 +2626,40 @@ rx_accept:
m_freem(m);
goto rx_next;
}
- sc->sc_rx_th.wr_rate =
- sc->sc_hwmap[ds->ds_rxstat.rs_rate];
+ rix = ds->ds_rxstat.rs_rate;
+ sc->sc_rx_th.wr_flags = sc->sc_hwflags[rix];
+ sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix];
sc->sc_rx_th.wr_antsignal = ds->ds_rxstat.rs_rssi;
sc->sc_rx_th.wr_antenna = ds->ds_rxstat.rs_antenna;
/* XXX TSF */
- bpf_mtap2(sc->sc_drvbpf,
- &sc->sc_rx_th, sc->sc_rx_th_len, m);
+ /*
+ * Gag, deal with hardware padding of headers. This
+ * only happens for QoS frames. We copy the 802.11
+ * header out-of-line and supply it separately, then
+ * adjust the mbuf chain. It would be better if we
+ * could just flag the packet in the radiotap header
+ * and have applications DTRT.
+ */
+ if (len > sizeof(struct ieee80211_qosframe)) {
+ data = mtod(m, const void *);
+ hdrsize = ieee80211_anyhdrsize(data);
+ if (hdrsize & 3) {
+ bcopy(data, &sc->sc_rx_wh, hdrsize);
+ hdrspace = roundup(hdrsize,
+ sizeof(u_int32_t));
+ m->m_data += hdrspace;
+ m->m_len -= hdrspace;
+ bpf_mtap2(sc->sc_drvbpf, &sc->sc_rx,
+ sc->sc_rx_rt_len + hdrsize, m);
+ m->m_data -= hdrspace;
+ m->m_len += hdrspace;
+ } else
+ bpf_mtap2(sc->sc_drvbpf,
+ &sc->sc_rx, sc->sc_rx_rt_len, m);
+ } else
+ bpf_mtap2(sc->sc_drvbpf,
+ &sc->sc_rx, sc->sc_rx_rt_len, m);
}
/*
@@ -3194,12 +3221,10 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m0);
if (sc->sc_drvbpf) {
- sc->sc_tx_th.wt_flags = 0;
- if (shortPreamble)
- sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ sc->sc_tx_th.wt_flags = sc->sc_hwflags[txrate];
if (iswep)
sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
- sc->sc_tx_th.wt_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
+ sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate];
sc->sc_tx_th.wt_txpower = ni->ni_txpower;
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
@@ -3649,6 +3674,7 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
{
struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_phymode mode;
+ u_int16_t flags;
/*
* Change channels and update the h/w rate map
@@ -3658,12 +3684,23 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
if (mode != sc->sc_curmode)
ath_setcurmode(sc, mode);
/*
- * Update BPF state.
+ * Update BPF state. NB: ethereal et. al. don't handle
+ * merged flags well so pick a unique mode for their use.
*/
+ if (IEEE80211_IS_CHAN_A(chan))
+ flags = IEEE80211_CHAN_A;
+ /* XXX 11g schizophrenia */
+ else if (IEEE80211_IS_CHAN_G(chan) ||
+ IEEE80211_IS_CHAN_PUREG(chan))
+ flags = IEEE80211_CHAN_G;
+ else
+ flags = IEEE80211_CHAN_B;
+ if (IEEE80211_IS_CHAN_T(chan))
+ flags |= IEEE80211_CHAN_TURBO;
sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
htole16(chan->ic_freq);
sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
- htole16(chan->ic_flags);
+ htole16(flags);
}
/*
@@ -4066,10 +4103,15 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
for (i = 0; i < rt->rateCount; i++)
sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i;
memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
+ memset(sc->sc_hwflags, 0, sizeof(sc->sc_hwflags));
for (i = 0; i < 32; i++) {
u_int8_t ix = rt->rateCodeToIndex[i];
- if (ix != 0xff)
- sc->sc_hwmap[i] = rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
+ if (ix == 0xff)
+ continue;
+ sc->sc_hwmap[i] = rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
+ if (rt->info[ix].shortPreamble ||
+ rt->info[ix].phy == IEEE80211_T_OFDM)
+ sc->sc_hwflags[i] |= IEEE80211_RADIOTAP_F_SHORTPRE;
}
sc->sc_currates = rt;
sc->sc_curmode = mode;
@@ -4488,8 +4530,8 @@ ath_bpfattach(struct ath_softc *sc)
sc->sc_tx_th.wt_ihdr.it_len = htole16(sc->sc_tx_th_len);
sc->sc_tx_th.wt_ihdr.it_present = htole32(ATH_TX_RADIOTAP_PRESENT);
- sc->sc_rx_th_len = roundup(sizeof(sc->sc_rx_th), sizeof(u_int32_t));
- sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_th_len);
+ sc->sc_rx_rt_len = roundup(sizeof(sc->sc_rx_th), sizeof(u_int32_t));
+ sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_rt_len);
sc->sc_rx_th.wr_ihdr.it_present = htole32(ATH_RX_RADIOTAP_PRESENT);
}
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index ffc05f2..4585801 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -182,6 +182,7 @@ struct ath_softc {
HAL_CHANNEL sc_curchan; /* current h/w channel */
u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */
u_int8_t sc_hwmap[32]; /* h/w rate ix to IEEE table */
+ u_int8_t sc_hwflags[32]; /* " " " to radiotap flags */
u_int8_t sc_protrix; /* protection rate index */
u_int sc_txantenna; /* tx antenna (fixed or auto) */
HAL_INT sc_imask; /* interrupt mask copy */
@@ -199,10 +200,13 @@ struct ath_softc {
} u_tx_rt;
int sc_tx_th_len;
union {
- struct ath_rx_radiotap_header th;
+ struct {
+ struct ath_rx_radiotap_header th;
+ struct ieee80211_qosframe wh;
+ } u;
u_int8_t pad[64];
} u_rx_rt;
- int sc_rx_th_len;
+ int sc_rx_rt_len;
struct task sc_fataltask; /* fatal int processing */
@@ -244,7 +248,9 @@ struct ath_softc {
};
#define sc_if sc_arp.ac_if
#define sc_tx_th u_tx_rt.th
-#define sc_rx_th u_rx_rt.th
+#define sc_rx u_rx_rt.u
+#define sc_rx_th sc_rx.th
+#define sc_rx_wh sc_rx.wh
#define ATH_LOCK_INIT(_sc) \
mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
OpenPOWER on IntegriCloud