summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2015-02-06 23:52:24 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2015-02-06 23:52:24 +0000
commit8a9300f5ce7c3a6e63c67274dc5cca83fc7efcaf (patch)
tree630b0c2540a5e206f20dfd7bc86915c8a21fb254 /sys
parentfb2209b5625d940883ff73242e34fc91802b893f (diff)
Add bpf(4) support to iwm(4). Makes tcpdump -i iwm0 work. Based on iwn(4).
ok deraadt
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwm.c165
-rw-r--r--sys/dev/pci/if_iwmreg.h11
-rw-r--r--sys/dev/pci/if_iwmvar.h55
3 files changed, 209 insertions, 22 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c
index 01e176e7311..4b35cf7a8cb 100644
--- a/sys/dev/pci/if_iwm.c
+++ b/sys/dev/pci/if_iwm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwm.c,v 1.1 2015/02/06 19:49:29 stsp Exp $ */
+/* $OpenBSD: if_iwm.c,v 1.2 2015/02/06 23:52:23 stsp Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -103,6 +103,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "bpfilter.h"
+
#include <sys/cdefs.h>
#include <sys/param.h>
@@ -125,7 +127,9 @@
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
+#if NBPFILTER > 0
#include <net/bpf.h>
+#endif
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
@@ -323,6 +327,7 @@ int iwm_mvm_get_signal_strength(struct iwm_softc *,
struct iwm_rx_phy_info *);
void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
+int iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *);
void iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
void iwm_mvm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
@@ -353,7 +358,7 @@ int iwm_mvm_send_cmd_pdu_status(struct iwm_softc *, uint8_t,
void iwm_free_resp(struct iwm_softc *, struct iwm_host_cmd *);
void iwm_cmd_done(struct iwm_softc *, struct iwm_rx_packet *);
void iwm_update_sched(struct iwm_softc *, int, int, uint8_t, uint16_t);
-void iwm_tx_fill_cmd(struct iwm_softc *, struct iwm_node *,
+const struct iwm_rate *iwm_tx_fill_cmd(struct iwm_softc *, struct iwm_node *,
struct ieee80211_frame *, struct iwm_tx_cmd *);
int iwm_tx(struct iwm_softc *, struct mbuf *, struct ieee80211_node *, int);
int iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *,
@@ -426,6 +431,9 @@ int iwm_match(struct device *, void *, void *);
int iwm_preinit(struct iwm_softc *);
void iwm_attach_hook(iwm_hookarg_t);
void iwm_attach(struct device *, struct device *, void *);
+#if NBPFILTER > 0
+void iwm_radiotap_attach(struct iwm_softc *);
+#endif
/*
* Firmware parser.
@@ -2993,6 +3001,27 @@ iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc,
}
/*
+ * Retrieve the average noise (in dBm) among receivers.
+ */
+int
+iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *stats)
+{
+ int i, total, nbant, noise;
+
+ total = nbant = noise = 0;
+ for (i = 0; i < 3; i++) {
+ noise = letoh32(stats->beacon_silence_rssi[i]) & 0xff;
+ if (noise) {
+ total += noise;
+ nbant++;
+ }
+ }
+
+ /* There should be at least one antenna but check anyway. */
+ return (nbant == 0) ? -127 : (total / nbant) - 107;
+}
+
+/*
* iwm_mvm_rx_rx_mpdu - IWM_REPLY_RX_MPDU_CMD handler
*
* Handles the actual data of the Rx packet from the fw
@@ -3066,6 +3095,50 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc,
ni = ieee80211_find_rxnode(ic, wh);
if (c)
ni->ni_chan = c;
+
+#if NBPFILTER > 0
+ if (sc->sc_drvbpf != NULL) {
+ struct mbuf mb;
+ struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+ tap->wr_flags = 0;
+ if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE))
+ tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ tap->wr_chan_freq =
+ htole16(ic->ic_channels[phy_info->channel].ic_freq);
+ tap->wr_chan_flags =
+ htole16(ic->ic_channels[phy_info->channel].ic_flags);
+ tap->wr_dbm_antsignal = (int8_t)rssi;
+ tap->wr_dbm_antnoise = (int8_t)sc->sc_noise;
+ tap->wr_tsft = phy_info->system_timestamp;
+ switch (phy_info->rate) {
+ /* CCK rates. */
+ case 10: tap->wr_rate = 2; break;
+ case 20: tap->wr_rate = 4; break;
+ case 55: tap->wr_rate = 11; break;
+ case 110: tap->wr_rate = 22; break;
+ /* OFDM rates. */
+ case 0xd: tap->wr_rate = 12; break;
+ case 0xf: tap->wr_rate = 18; break;
+ case 0x5: tap->wr_rate = 24; break;
+ case 0x7: tap->wr_rate = 36; break;
+ case 0x9: tap->wr_rate = 48; break;
+ case 0xb: tap->wr_rate = 72; break;
+ case 0x1: tap->wr_rate = 96; break;
+ case 0x3: tap->wr_rate = 108; break;
+ /* Unknown rate: should not happen. */
+ default: tap->wr_rate = 0;
+ }
+
+ mb.m_data = (caddr_t)tap;
+ mb.m_len = sc->sc_rxtap_len;
+ mb.m_next = m;
+ mb.m_nextpkt = NULL;
+ mb.m_type = 0;
+ mb.m_flags = 0;
+ bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
+ }
+#endif
ieee80211_input(IC2IFP(ic), m, ni, &rxi);
ieee80211_release_node(ic, ni);
}
@@ -3630,8 +3703,9 @@ iwm_update_sched(struct iwm_softc *sc, int qid, int idx, uint8_t sta_id,
/*
* Fill in various bit for management frames, and leave them
* unfilled for data frames (firmware takes care of that).
+ * Return the selected TX rate.
*/
-void
+const struct iwm_rate *
iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
struct ieee80211_frame *wh, struct iwm_tx_cmd *tx)
{
@@ -3652,7 +3726,7 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
}
tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
DPRINTFN(12, ("start with txrate %d\n", tx->initial_rate_index));
- return;
+ return &iwm_rates[tx->initial_rate_index];
}
/* for non-data, use the lowest supported rate */
@@ -3663,6 +3737,8 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
if (IWM_RIDX_IS_CCK(ridx))
rate_flags |= IWM_RATE_MCS_CCK_MSK;
tx->rate_n_flags = htole32(rate_flags | rinfo->plcp);
+
+ return rinfo;
}
#define TB0_SIZE 16
@@ -3679,6 +3755,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
struct ieee80211_frame *wh;
struct ieee80211_key *k = NULL;
struct mbuf *m1;
+ const struct iwm_rate *rinfo;
uint32_t flags;
u_int hdrlen;
bus_dma_segment_t *seg;
@@ -3705,6 +3782,42 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
memset(desc, 0, sizeof(*desc));
data = &ring->data[ring->cur];
+ /* Fill out iwm_tx_cmd to send to the firmware */
+ cmd = &ring->cmd[ring->cur];
+ cmd->hdr.code = IWM_TX_CMD;
+ cmd->hdr.flags = 0;
+ cmd->hdr.qid = ring->qid;
+ cmd->hdr.idx = ring->cur;
+
+ tx = (void *)cmd->data;
+ memset(tx, 0, sizeof(*tx));
+
+ rinfo = iwm_tx_fill_cmd(sc, in, wh, tx);
+
+#if NBPFILTER > 0
+ if (sc->sc_drvbpf != NULL) {
+ struct mbuf mb;
+ struct iwm_tx_radiotap_header *tap = &sc->sc_txtap;
+
+ tap->wt_flags = 0;
+ tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
+ tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags);
+ tap->wt_rate = rinfo->rate;
+ tap->wt_hwqueue = ac;
+ if ((ic->ic_flags & IEEE80211_F_WEPON) &&
+ (wh->i_fc[1] & IEEE80211_FC1_PROTECTED))
+ tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ mb.m_data = (caddr_t)tap;
+ mb.m_len = sc->sc_txtap_len;
+ mb.m_next = m;
+ mb.m_nextpkt = NULL;
+ mb.m_type = 0;
+ mb.m_flags = 0;
+ bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
+ }
+#endif
+
/* Encrypt the frame if need be. */
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
/* Retrieve key for TX && do software encryption. */
@@ -3716,16 +3829,6 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
}
totlen = m->m_pkthdr.len;
- /* Fill out iwm_tx_cmd to send to the firmware */
- cmd = &ring->cmd[ring->cur];
- cmd->hdr.code = IWM_TX_CMD;
- cmd->hdr.flags = 0;
- cmd->hdr.qid = ring->qid;
- cmd->hdr.idx = ring->cur;
-
- tx = (void *)cmd->data;
- memset(tx, 0, sizeof(*tx));
-
flags = 0;
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
flags |= IWM_TX_CMD_FLG_ACK;
@@ -3781,8 +3884,6 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
tx->sec_ctl = 0;
tx->tx_flags |= htole32(flags);
- iwm_tx_fill_cmd(sc, in, wh, tx);
-
/* Trim 802.11 header. */
m_adj(m, hdrlen);
@@ -5553,12 +5654,20 @@ iwm_start(struct ifnet *ifp)
ifp->if_oerrors++;
continue;
}
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
ifp->if_oerrors++;
continue;
}
sendit:
+#if NBPFILTER > 0
+ if (ic->ic_rawbpf != NULL)
+ bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
+#endif
if (iwm_tx(sc, m, ni, ac) != 0) {
ieee80211_release_node(ic, ni);
ifp->if_oerrors++;
@@ -5945,6 +6054,7 @@ iwm_notif_intr(struct iwm_softc *sc)
struct iwm_notif_statistics *stats;
SYNC_RESP_STRUCT(stats, pkt);
memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats));
+ sc->sc_noise = iwm_get_noise(&stats->rx.general);
break; }
case IWM_NVM_ACCESS_CMD:
@@ -6377,6 +6487,9 @@ iwm_attach_hook(iwm_hookarg_t arg)
ic->ic_newstate = iwm_newstate;
ieee80211_media_init(ifp, iwm_media_change, ieee80211_media_status);
+#if NBPFILTER > 0
+ iwm_radiotap_attach(sc);
+#endif
timeout_set(&sc->sc_calib_to, iwm_calib_timeout, sc);
return;
@@ -6475,6 +6588,26 @@ iwm_attach(struct device *parent, struct device *self, void *aux)
iwm_attach_hook(sc);
}
+#if NBPFILTER > 0
+/*
+ * Attach the interface to 802.11 radiotap.
+ */
+void
+iwm_radiotap_attach(struct iwm_softc *sc)
+{
+ bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
+ sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
+
+ sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
+ sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
+ sc->sc_rxtap.wr_ihdr.it_present = htole32(IWM_RX_RADIOTAP_PRESENT);
+
+ sc->sc_txtap_len = sizeof sc->sc_txtapu;
+ sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
+ sc->sc_txtap.wt_ihdr.it_present = htole32(IWM_TX_RADIOTAP_PRESENT);
+}
+#endif
+
struct cfdriver iwm_cd = {
NULL, "iwm", DV_IFNET
};
diff --git a/sys/dev/pci/if_iwmreg.h b/sys/dev/pci/if_iwmreg.h
index ac3acab9c47..5dc4b1ef40f 100644
--- a/sys/dev/pci/if_iwmreg.h
+++ b/sys/dev/pci/if_iwmreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmreg.h,v 1.1 2015/02/06 19:49:29 stsp Exp $ */
+/* $OpenBSD: if_iwmreg.h,v 1.2 2015/02/06 23:52:23 stsp Exp $ */
/******************************************************************************
*
@@ -2402,9 +2402,12 @@ struct iwm_rx_phy_info {
uint64_t timestamp;
uint32_t beacon_time_stamp;
uint16_t phy_flags;
+#define IWM_PHY_INFO_FLAG_SHPREAMBLE (1 << 2)
uint16_t channel;
uint32_t non_cfg_phy[IWM_RX_INFO_PHY_CNT];
- uint32_t rate_n_flags;
+ uint8_t rate;
+ uint8_t rflags;
+ uint16_t xrflags;
uint32_t byte_count;
uint16_t mac_active_msk;
uint16_t frame_time;
@@ -2641,9 +2644,7 @@ struct iwm_mvm_statistics_rx_non_phy {
* ADC was in saturation */
uint32_t ina_detection_search_time;/* total time (in 0.8us) searched
* for INA */
- uint32_t beacon_silence_rssi_a; /* RSSI silence after beacon frame */
- uint32_t beacon_silence_rssi_b; /* RSSI silence after beacon frame */
- uint32_t beacon_silence_rssi_c; /* RSSI silence after beacon frame */
+ uint32_t beacon_silence_rssi[3];/* RSSI silence after beacon frame */
uint32_t interference_data_flag; /* flag for interference data
* availability. 1 when data is
* available. */
diff --git a/sys/dev/pci/if_iwmvar.h b/sys/dev/pci/if_iwmvar.h
index 2d47ad80fa8..84d90a617f6 100644
--- a/sys/dev/pci/if_iwmvar.h
+++ b/sys/dev/pci/if_iwmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmvar.h,v 1.1 2015/02/06 19:49:29 stsp Exp $ */
+/* $OpenBSD: if_iwmvar.h,v 1.2 2015/02/06 23:52:23 stsp Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -103,6 +103,40 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct iwm_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ uint64_t wr_tsft;
+ uint8_t wr_flags;
+ uint8_t wr_rate;
+ uint16_t wr_chan_freq;
+ uint16_t wr_chan_flags;
+ int8_t wr_dbm_antsignal;
+ int8_t wr_dbm_antnoise;
+} __packed;
+
+#define IWM_RX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE))
+
+struct iwm_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ uint8_t wt_flags;
+ uint8_t wt_rate;
+ uint16_t wt_chan_freq;
+ uint16_t wt_chan_flags;
+ uint8_t wt_hwqueue;
+} __packed;
+
+#define IWM_TX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_HWQUEUE))
+
#define IWM_UCODE_SECT_MAX 6
#define IWM_FWNAME "iwm-7260-9"
#define IWM_FWDMASEGSZ (192*1024)
@@ -435,6 +469,25 @@ struct iwm_softc {
struct iwm_mvm_phy_ctxt sc_phyctxt[IWM_NUM_PHY_CTX];
struct iwm_notif_statistics sc_stats;
+ int sc_noise;
+
+#if NBPFILTER > 0
+ caddr_t sc_drvbpf;
+
+ union {
+ struct iwm_rx_radiotap_header th;
+ uint8_t pad[IEEE80211_RADIOTAP_HDRLEN];
+ } sc_rxtapu;
+#define sc_rxtap sc_rxtapu.th
+ int sc_rxtap_len;
+
+ union {
+ struct iwm_tx_radiotap_header th;
+ uint8_t pad[IEEE80211_RADIOTAP_HDRLEN];
+ } sc_txtapu;
+#define sc_txtap sc_txtapu.th
+ int sc_txtap_len;
+#endif
};
struct iwm_node {