Looks good on a 7260.

ok ccardenas@

+--+
Carlos

On Wed, May 23, 2018 at 12:31:45PM +0200, Stefan Sperling wrote:
> This diff implements monitor mode for iwm(4).
> 
> To use it, enable 11n mode, monitor mode, and configure a channel (e.g. 11):
> 
>       ifconfig iwm0 mode 11n mediaopt monitor
>       ifconfig iwm0 chan 11
>       ifconfig iwm0 up
> 
> This command should now display wireless frames on the air:
> 
>       tcpdump -n -i iwm0 -y IEEE802_11_RADIO -v
> 
> Record frames with tcpdump like this (pcap file can be viewed in wireshark):
> 
>       tcpdump -n -i iwm0 -s 4096 -y IEEE802_11_RADIO -w /tmp/iwm.pcap
> 
> Note that 11n/11ac frames sent with >= 40 MHz channel width won't be
> captured. The hardware could do it but our stack is not passing the
> necessary configuration parameters to the driver, so the driver cannot
> configure the hardware appropriately (a similar problem as bwfm(4) has
> with our stack's incomplete 11n support).
> But the corresponding leading RTS and trailing BlockAck frames can be
> captured, which allows us to manually deduce the presence of such frames.  
> 
> Tested on a 7265 device.
> 
> ok?
> 
> Index: if_iwm.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
> retrieving revision 1.229
> diff -u -p -r1.229 if_iwm.c
> --- if_iwm.c  15 May 2018 19:48:23 -0000      1.229
> +++ if_iwm.c  23 May 2018 10:10:45 -0000
> @@ -426,7 +426,7 @@ uint8_t   iwm_ridx2rate(struct ieee80211_r
>  int  iwm_rval2ridx(int);
>  void iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *);
>  void iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *,
> -         struct iwm_mac_ctx_cmd *, uint32_t, int);
> +         struct iwm_mac_ctx_cmd *, uint32_t);
>  void iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *, struct iwm_node *,
>           struct iwm_mac_data_sta *, int);
>  int  iwm_mac_ctxt_cmd(struct iwm_softc *, struct iwm_node *, uint32_t, int);
> @@ -4446,6 +4446,7 @@ void
>  iwm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in,
>      struct iwm_mac_power_cmd *cmd)
>  {
> +     struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_node *ni = &in->in_ni;
>       int dtim_period, dtim_msec, keep_alive;
>  
> @@ -4467,7 +4468,8 @@ iwm_power_build_cmd(struct iwm_softc *sc
>       keep_alive = roundup(keep_alive, 1000) / 1000;
>       cmd->keep_alive_seconds = htole16(keep_alive);
>  
> -     cmd->flags = htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK);
> +     if (ic->ic_opmode != IEEE80211_M_MONITOR)
> +             cmd->flags = htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK);
>  }
>  
>  int
> @@ -4494,13 +4496,15 @@ iwm_power_mac_update_mode(struct iwm_sof
>  int
>  iwm_power_update_device(struct iwm_softc *sc)
>  {
> -     struct iwm_device_power_cmd cmd = {
> -             .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
> -     };
> +     struct iwm_device_power_cmd cmd = { };
> +     struct ieee80211com *ic = &sc->sc_ic;
>  
>       if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
>               return 0;
>  
> +     if (ic->ic_opmode != IEEE80211_M_MONITOR)
> +             cmd.flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
> +
>       return iwm_send_cmd_pdu(sc,
>           IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd);
>  }
> @@ -4562,7 +4566,12 @@ iwm_add_sta_cmd(struct iwm_softc *sc, st
>                       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
> @@ -5230,7 +5239,7 @@ iwm_ack_rates(struct iwm_softc *sc, stru
>  
>  void
>  iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
> -    struct iwm_mac_ctx_cmd *cmd, uint32_t action, int assoc)
> +    struct iwm_mac_ctx_cmd *cmd, uint32_t action)
>  {
>  #define IWM_EXP2(x)  ((1 << (x)) - 1)        /* CWmin = 2^ECWmin - 1 */
>       struct ieee80211com *ic = &sc->sc_ic;
> @@ -5242,12 +5251,21 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc
>           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);
> -     IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             IEEE80211_ADDR_COPY(cmd->bssid_addr, etherbroadcastaddr);
> +             return;
> +     }
>  
> +     IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
>       iwm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates);
>       cmd->cck_rates = htole32(cck_ack_rates);
>       cmd->ofdm_rates = htole32(ofdm_ack_rates);
> @@ -5332,6 +5350,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;
>       int active = (sc->sc_flags & IWM_FLAG_MAC_ACTIVE);
> @@ -5343,11 +5362,19 @@ iwm_mac_ctxt_cmd(struct iwm_softc *sc, s
>  
>       memset(&cmd, 0, sizeof(cmd));
>  
> -     iwm_mac_ctxt_cmd_common(sc, in, &cmd, action, assoc);
> +     iwm_mac_ctxt_cmd_common(sc, in, &cmd, action);
>  
> -     /* 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);
> @@ -5564,7 +5591,10 @@ iwm_auth(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> -     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) {
> @@ -5598,6 +5628,9 @@ iwm_auth(struct iwm_softc *sc)
>       }
>       sc->sc_flags |= IWM_FLAG_STA_ACTIVE;
>  
> +     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.
> @@ -5728,8 +5761,16 @@ iwm_run(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             /* Add a MAC context and a sniffing STA. */
> +             err = iwm_auth(sc);
> +             if (err)
> +                     return err;
> +     }
> +
>       /* 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);
> @@ -5797,6 +5838,11 @@ iwm_run(struct iwm_softc *sc)
>       ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
>       ieee80211_mira_node_init(&in->in_mn);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             iwm_led_blink_start(sc);
> +             return 0;
> +     }
> +
>       /* Start at lowest available bit-rate, AMRR will raise. */
>       in->in_ni.ni_txrate = 0;
>       in->in_ni.ni_txmcs = 0;
> @@ -5817,6 +5863,9 @@ iwm_run_stop(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +             iwm_led_blink_stop(sc);
> +
>       err = iwm_sf_config(sc, IWM_SF_INIT_OFF);
>       if (err)
>               return err;
> @@ -6565,6 +6614,12 @@ iwm_init(struct ifnet *ifp)
>       ifq_clr_oactive(&ifp->if_snd);
>       ifp->if_flags |= IFF_RUNNING;
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             ic->ic_bss->ni_chan = ic->ic_ibss_chan;
> +             ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
> +             return 0;
> +     }
> +
>       ieee80211_begin_scan(ifp);
>  
>       /* 
> @@ -7894,6 +7949,7 @@ iwm_attach(struct device *parent, struct
>           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 */
>  
> 

Reply via email to