summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2017-04-24 09:48:43 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2017-04-24 09:48:43 +0000
commit068a62d27cc80ed1e491d578c3d3ea8694b93255 (patch)
treeb7c3a1692e172d43037253b9eb8106bb8f9afca6
parent4e43d63e05896dceca078829f573ab15b5d17d60 (diff)
Implement monitor mode support for iwm(4).
The magic commands to capture raw 802.11 frames on e.g. channel 1 are: ifconfig iwm0 mediaopt monitor chan 1 tcpdump -n -i iwm0 -y IEEE802_11_RADIO -s 4096 -w /tmp/iwm.pcap ifconfig iwm0 -mediaopt monitor -chan
-rw-r--r--sys/dev/pci/if_iwm.c75
1 files changed, 65 insertions, 10 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c
index f5deacb98fd..fd3aa8430b7 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.171 2017/04/24 09:31:31 stsp Exp $ */
+/* $OpenBSD: if_iwm.c,v 1.172 2017/04/24 09:48:42 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -4384,7 +4384,12 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node *in, int update)
add_sta_cmd.tfd_queue_msk |=
htole32(1 << iwm_ac_to_tx_fifo[ac]);
}
- IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ IEEE80211_ADDR_COPY(&add_sta_cmd.addr,
+ etherbroadcastaddr);
+ else
+ IEEE80211_ADDR_COPY(&add_sta_cmd.addr,
+ in->in_ni.ni_bssid);
}
add_sta_cmd.add_modify = update ? 1 : 0;
add_sta_cmd.station_flags_msk
@@ -5024,7 +5029,13 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
in->in_color));
cmd->action = htole32(action);
- cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ cmd->mac_type = htole32(IWM_FW_MAC_TYPE_LISTENER);
+ else if (ic->ic_opmode == IEEE80211_M_STA)
+ cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
+ else
+ panic("unsupported operating mode %d\n", ic->ic_opmode);
+
cmd->tsf_id = htole32(IWM_TSF_ID_A);
IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr);
@@ -5114,6 +5125,7 @@ int
iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action,
int assoc)
{
+ struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = &in->in_ni;
struct iwm_mac_ctx_cmd cmd;
@@ -5121,9 +5133,17 @@ iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action,
iwm_mac_ctxt_cmd_common(sc, in, &cmd, action, assoc);
- /* Allow beacons to pass through as long as we are not associated or we
- * do not have dtim period information */
- if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod)
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ cmd.filter_flags = htole32(IWM_MAC_FILTER_IN_PROMISC |
+ IWM_MAC_FILTER_IN_CONTROL_AND_MGMT |
+ IWM_MAC_FILTER_IN_BEACON |
+ IWM_MAC_FILTER_IN_PROBE_REQUEST |
+ IWM_MAC_FILTER_IN_CRC32);
+ } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod)
+ /*
+ * Allow beacons to pass through as long as we are not
+ * associated or we do not have dtim period information.
+ */
cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON);
else
iwm_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc);
@@ -5210,7 +5230,10 @@ iwm_auth(struct iwm_softc *sc)
if (err)
return err;
- sc->sc_phyctxt[0].channel = in->in_ni.ni_chan;
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ sc->sc_phyctxt[0].channel = ic->ic_ibss_chan;
+ else
+ sc->sc_phyctxt[0].channel = in->in_ni.ni_chan;
err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0], 1, 1,
IWM_FW_CTXT_ACTION_MODIFY, 0);
if (err)
@@ -5238,6 +5261,9 @@ iwm_auth(struct iwm_softc *sc)
return err;
}
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ return 0;
+
/*
* Prevent the FW from wandering off channel during association
* by "protecting" the session with a time event.
@@ -5465,8 +5491,12 @@ iwm_newstate_task(void *psc)
if (ostate == IEEE80211_S_SCAN && nstate != ostate)
iwm_led_blink_stop(sc);
- if (ostate == IEEE80211_S_RUN && nstate != ostate)
+ if (ostate == IEEE80211_S_RUN && nstate != ostate) {
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ iwm_led_blink_stop(sc);
iwm_disable_beacon_filter(sc);
+ }
+
/* Reset the device if moving out of AUTH, ASSOC, or RUN. */
/* XXX Is there a way to switch states without a full reset? */
@@ -5523,8 +5553,16 @@ iwm_newstate_task(void *psc)
break;
case IEEE80211_S_RUN:
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ /* Add a MAC context and a sniffing STA. */
+ err = iwm_auth(sc);
+ if (err)
+ return;
+ }
+
/* Configure Rx chains for MIMO. */
- if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) &&
+ if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
+ (in->in_ni.ni_flags & IEEE80211_NODE_HT)) &&
!sc->sc_nvm.sku_cap_mimo_disable) {
err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0],
2, 2, IWM_FW_CTXT_ACTION_MODIFY, 0);
@@ -5535,6 +5573,17 @@ iwm_newstate_task(void *psc)
}
}
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ err = iwm_update_quotas(sc, in);
+ if (err) {
+ printf("%s: could not update quotas "
+ "(error %d)\n", DEVNAME(sc), err);
+ return;
+ }
+ iwm_led_blink_start(sc);
+ break;
+ }
+
/* We have now been assigned an associd by the AP. */
err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1);
if (err) {
@@ -5981,6 +6030,7 @@ int
iwm_init(struct ifnet *ifp)
{
struct iwm_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
int err;
if (sc->sc_flags & IWM_FLAG_HW_INITED) {
@@ -5998,7 +6048,11 @@ iwm_init(struct ifnet *ifp)
ifq_clr_oactive(&ifp->if_snd);
ifp->if_flags |= IFF_RUNNING;
- ieee80211_begin_scan(ifp);
+ if (ic->ic_opmode != IEEE80211_M_MONITOR)
+ ieee80211_begin_scan(ifp);
+ else
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+
sc->sc_flags |= IWM_FLAG_HW_INITED;
return 0;
@@ -7265,6 +7319,7 @@ iwm_attach(struct device *parent, struct device *self, void *aux)
IEEE80211_C_RSN | /* WPA/RSN */
IEEE80211_C_SCANALL | /* device scans all channels at once */
IEEE80211_C_SCANALLBAND | /* device scans all bands at once */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SHPREAMBLE; /* short preamble supported */