iwn: add promiscuous mode support.

Tested with Intel 6205, STA / MONITOR modes.
This commit is contained in:
Andriy Voskoboinyk 2017-03-08 22:49:22 +00:00
parent 43ee32f7df
commit 9d5228cd85
3 changed files with 156 additions and 23 deletions

View File

@ -249,6 +249,8 @@ static int iwn_set_link_quality(struct iwn_softc *,
struct ieee80211_node *);
static int iwn_add_broadcast_node(struct iwn_softc *, int);
static int iwn_updateedca(struct ieee80211com *);
static void iwn_set_promisc(struct iwn_softc *);
static void iwn_update_promisc(struct ieee80211com *);
static void iwn_update_mcast(struct ieee80211com *);
static void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
static int iwn_set_critical_temp(struct iwn_softc *);
@ -278,6 +280,9 @@ static int iwn_set_pslevel(struct iwn_softc *, int, int, int);
static int iwn_send_btcoex(struct iwn_softc *);
static int iwn_send_advanced_btcoex(struct iwn_softc *);
static int iwn5000_runtime_calib(struct iwn_softc *);
static int iwn_check_bss_filter(struct iwn_softc *);
static int iwn4965_rxon_assoc(struct iwn_softc *, int);
static int iwn5000_rxon_assoc(struct iwn_softc *, int);
static int iwn_send_rxon(struct iwn_softc *, int, int);
static int iwn_config(struct iwn_softc *);
static int iwn_scan(struct iwn_softc *, struct ieee80211vap *,
@ -662,6 +667,7 @@ iwn_attach(device_t dev)
ic->ic_addba_stop = iwn_ampdu_tx_stop;
ic->ic_newassoc = iwn_newassoc;
ic->ic_wme.wme_update = iwn_updateedca;
ic->ic_update_promisc = iwn_update_promisc;
ic->ic_update_mcast = iwn_update_mcast;
ic->ic_scan_start = iwn_scan_start;
ic->ic_scan_end = iwn_scan_end;
@ -1227,6 +1233,7 @@ iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
ops->set_txpower = iwn4965_set_txpower;
ops->init_gains = iwn4965_init_gains;
ops->set_gains = iwn4965_set_gains;
ops->rxon_assoc = iwn4965_rxon_assoc;
ops->add_node = iwn4965_add_node;
ops->tx_done = iwn4965_tx_done;
ops->ampdu_tx_start = iwn4965_ampdu_tx_start;
@ -1271,6 +1278,7 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
ops->set_txpower = iwn5000_set_txpower;
ops->init_gains = iwn5000_init_gains;
ops->set_gains = iwn5000_set_gains;
ops->rxon_assoc = iwn5000_rxon_assoc;
ops->add_node = iwn5000_add_node;
ops->tx_done = iwn5000_tx_done;
ops->ampdu_tx_start = iwn5000_ampdu_tx_start;
@ -5427,6 +5435,43 @@ iwn_updateedca(struct ieee80211com *ic)
#undef IWN_EXP2
}
static void
iwn_set_promisc(struct iwn_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
uint32_t promisc_filter;
promisc_filter = IWN_FILTER_CTL | IWN_FILTER_PROMISC;
if (ic->ic_promisc > 0 || ic->ic_opmode == IEEE80211_M_MONITOR)
sc->rxon->filter |= htole32(promisc_filter);
else
sc->rxon->filter &= ~htole32(promisc_filter);
}
static void
iwn_update_promisc(struct ieee80211com *ic)
{
struct iwn_softc *sc = ic->ic_softc;
int error;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
return; /* nothing to do */
IWN_LOCK(sc);
if (!(sc->sc_flags & IWN_FLAG_RUNNING)) {
IWN_UNLOCK(sc);
return;
}
iwn_set_promisc(sc);
if ((error = iwn_send_rxon(sc, 1, 1)) != 0) {
device_printf(sc->sc_dev,
"%s: could not send RXON, error %d\n",
__func__, error);
}
IWN_UNLOCK(sc);
}
static void
iwn_update_mcast(struct ieee80211com *ic)
{
@ -6534,6 +6579,52 @@ iwn_get_rxon_ht_flags(struct iwn_softc *sc, struct ieee80211_channel *c)
return (htflags);
}
static int
iwn_check_bss_filter(struct iwn_softc *sc)
{
return ((sc->rxon->filter & htole32(IWN_FILTER_BSS)) != 0);
}
static int
iwn4965_rxon_assoc(struct iwn_softc *sc, int async)
{
struct iwn4965_rxon_assoc cmd;
struct iwn_rxon *rxon = sc->rxon;
cmd.flags = rxon->flags;
cmd.filter = rxon->filter;
cmd.ofdm_mask = rxon->ofdm_mask;
cmd.cck_mask = rxon->cck_mask;
cmd.ht_single_mask = rxon->ht_single_mask;
cmd.ht_dual_mask = rxon->ht_dual_mask;
cmd.rxchain = rxon->rxchain;
cmd.reserved = 0;
return (iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &cmd, sizeof(cmd), async));
}
static int
iwn5000_rxon_assoc(struct iwn_softc *sc, int async)
{
struct iwn5000_rxon_assoc cmd;
struct iwn_rxon *rxon = sc->rxon;
cmd.flags = rxon->flags;
cmd.filter = rxon->filter;
cmd.ofdm_mask = rxon->ofdm_mask;
cmd.cck_mask = rxon->cck_mask;
cmd.reserved1 = 0;
cmd.ht_single_mask = rxon->ht_single_mask;
cmd.ht_dual_mask = rxon->ht_dual_mask;
cmd.ht_triple_mask = rxon->ht_triple_mask;
cmd.reserved2 = 0;
cmd.rxchain = rxon->rxchain;
cmd.acquisition = rxon->acquisition;
cmd.reserved3 = 0;
return (iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &cmd, sizeof(cmd), async));
}
static int
iwn_send_rxon(struct iwn_softc *sc, int assoc, int async)
{
@ -6542,33 +6633,46 @@ iwn_send_rxon(struct iwn_softc *sc, int assoc, int async)
IWN_LOCK_ASSERT(sc);
if (sc->sc_is_scanning)
device_printf(sc->sc_dev,
"%s: is_scanning set, before RXON\n",
__func__);
error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, async);
if (error != 0) {
device_printf(sc->sc_dev, "%s: RXON command failed\n",
__func__);
return (error);
}
/*
* Reconfiguring RXON clears the firmware nodes table so we must
* add the broadcast node again.
*/
if ((sc->rxon->filter & htole32(IWN_FILTER_BSS)) == 0) {
if ((error = iwn_add_broadcast_node(sc, async)) != 0) {
if (assoc && iwn_check_bss_filter(sc) != 0) {
error = ops->rxon_assoc(sc, async);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not add broadcast node\n", __func__);
"%s: RXON_ASSOC command failed, error %d\n",
__func__, error);
return (error);
}
} else {
if (sc->sc_is_scanning)
device_printf(sc->sc_dev,
"%s: is_scanning set, before RXON\n",
__func__);
error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, async);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: RXON command failed, error %d\n",
__func__, error);
return (error);
}
/*
* Reconfiguring RXON clears the firmware nodes table so
* we must add the broadcast node again.
*/
if (iwn_check_bss_filter(sc) == 0 &&
(error = iwn_add_broadcast_node(sc, async)) != 0) {
device_printf(sc->sc_dev,
"%s: could not add broadcast node, error %d\n",
__func__, error);
return (error);
}
}
/* Configuration has changed, set TX power accordingly. */
if ((error = ops->set_txpower(sc, async)) != 0) {
device_printf(sc->sc_dev, "%s: could not set TX power\n",
__func__);
device_printf(sc->sc_dev,
"%s: could not set TX power, error %d\n",
__func__, error);
return (error);
}
@ -6669,20 +6773,20 @@ iwn_config(struct iwn_softc *sc)
sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
sc->rxon->filter = htole32(IWN_FILTER_MULTICAST);
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
sc->rxon->mode = IWN_MODE_STA;
sc->rxon->filter = htole32(IWN_FILTER_MULTICAST);
break;
case IEEE80211_M_MONITOR:
sc->rxon->mode = IWN_MODE_MONITOR;
sc->rxon->filter = htole32(IWN_FILTER_MULTICAST |
IWN_FILTER_CTL | IWN_FILTER_PROMISC);
break;
default:
/* Should not get there. */
break;
}
iwn_set_promisc(sc);
sc->rxon->cck_mask = 0x0f; /* not yet negotiated */
sc->rxon->ofdm_mask = 0xff; /* not yet negotiated */
sc->rxon->ht_single_mask = 0xff;

View File

@ -617,6 +617,34 @@ struct iwn_rxon {
#define IWN4965_RXONSZ (sizeof (struct iwn_rxon) - 6)
#define IWN5000_RXONSZ (sizeof (struct iwn_rxon))
/* Structure for command IWN_CMD_RXON_ASSOC (4965AGN only.) */
struct iwn4965_rxon_assoc {
uint32_t flags;
uint32_t filter;
uint8_t ofdm_mask;
uint8_t cck_mask;
uint8_t ht_single_mask;
uint8_t ht_dual_mask;
uint16_t rxchain;
uint16_t reserved;
} __packed;
/* Structure for command IWN_CMD_RXON_ASSOC (5000 Series only.) */
struct iwn5000_rxon_assoc {
uint32_t flags;
uint32_t filter;
uint8_t ofdm_mask;
uint8_t cck_mask;
uint16_t reserved1;
uint8_t ht_single_mask;
uint8_t ht_dual_mask;
uint8_t ht_triple_mask;
uint8_t reserved2;
uint16_t rxchain;
uint16_t acquisition;
uint32_t reserved3;
} __packed;
/* Structure for command IWN_CMD_ASSOCIATE. */
struct iwn_assoc {
uint32_t flags;

View File

@ -209,6 +209,7 @@ struct iwn_ops {
int (*set_txpower)(struct iwn_softc *, int);
int (*init_gains)(struct iwn_softc *);
int (*set_gains)(struct iwn_softc *);
int (*rxon_assoc)(struct iwn_softc *, int);
int (*add_node)(struct iwn_softc *, struct iwn_node_info *,
int);
void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *,