From: Grazvydas Ignotas Date: Tue, 26 Oct 2010 15:51:49 +0000 (+0300) Subject: wl1251: implement filtering X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-wifi.git;a=commitdiff_plain;h=4213d143b82b07dfc5cd9a05c2693f15c087e5d4 wl1251: implement filtering Finish up filtering code and enable it. mac80211 no longer requires to be atomic in .configure_filter callback, so remove filter_work. The new filtering code makes sure it doesn't enable BSSID filtering while BSSID is not set so that association works properly. This allows removing hack in wl1251_cmd_join. Signed-off-by: Grazvydas Ignotas --- diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 4a3f195..46dd160 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -49,6 +49,7 @@ enum { DEBUG_MAC80211 = BIT(11), DEBUG_CMD = BIT(12), DEBUG_ACX = BIT(13), + DEBUG_FILTERS = BIT(14), DEBUG_ALL = ~0, }; @@ -310,7 +311,6 @@ struct wl1251 { bool tx_queue_stopped; struct work_struct tx_work; - struct work_struct filter_work; /* Pending TX frames */ struct sk_buff *tx_frames[16]; @@ -351,6 +351,7 @@ struct wl1251 { unsigned int tx_mgmt_frm_rate; unsigned int tx_mgmt_frm_mod; + unsigned int mac80211_filters; unsigned int rx_config; unsigned int rx_filter; diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index a64dbd3..c0cdcd0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -300,15 +300,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; - /* - * FIXME: disable temporarily all filters because after commit - * 9cef8737 "mac80211: fix managed mode BSSID handling" broke - * association. The filter logic needs to be implemented properly - * and once that is done, this hack can be removed. - */ - join->rx_config_options = 0; - join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 5e09161..8b3e78e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -323,6 +323,46 @@ out: mutex_unlock(&wl->mutex); } +static void wl1251_convert_filters(struct wl1251 *wl, + unsigned int mac80211_filters) +{ + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + + if (mac80211_filters & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_UNI_FILTER_EN; + } + if (mac80211_filters & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (mac80211_filters & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (mac80211_filters & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (mac80211_filters & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (mac80211_filters & FIF_OTHER_BSS) + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + if (mac80211_filters & FIF_PROBE_REQ) + wl->rx_filter |= CFG_RX_PREQ_EN; + + /* + * If we have no associated BSSID, the filter must be disabled + * or else association will break + */ + if (is_zero_ether_addr(wl->bssid)) + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + + wl1251_debug(DEBUG_FILTERS, "rx_config %04x, rx_filter %04x", + wl->rx_config, wl->rx_filter); +} + static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_period) { @@ -335,6 +375,8 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, if (ret < 0) goto out; + /* Join uses filters, update them */ + wl1251_convert_filters(wl, wl->mac80211_filters); ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, dtim_period); @@ -349,33 +391,6 @@ out: return ret; } -static void wl1251_filter_work(struct work_struct *work) -{ - struct wl1251 *wl = - container_of(work, struct wl1251, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1251 *wl = hw->priv; @@ -483,7 +498,6 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); mutex_lock(&wl->mutex); @@ -676,15 +690,18 @@ out: FIF_FCSFAIL | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_CONTROL | \ - FIF_OTHER_BSS) + FIF_OTHER_BSS | \ + FIF_PROBE_REQ) static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *total,u64 multicast) { struct wl1251 *wl = hw->priv; + int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); + wl1251_debug(DEBUG_FILTERS, "configure filter %x %x", *total, changed); *total &= WL1251_SUPPORTED_FILTERS; changed &= WL1251_SUPPORTED_FILTERS; @@ -693,38 +710,25 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, /* no filters which we support changed */ return; - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + mutex_lock(&wl->mutex); - wl->rx_config = WL1251_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1251_DEFAULT_RX_FILTER; + wl->mac80211_filters = *total; + wl1251_convert_filters(wl, *total); - if (*total & FIF_PROMISC_IN_BSS) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - wl->rx_config |= CFG_RX_ALL_GOOD; - } - if (*total & FIF_ALLMULTI) - /* - * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive - * all multicast frames - */ - wl->rx_config &= ~CFG_MC_FILTER_EN; - if (*total & FIF_FCSFAIL) - wl->rx_filter |= CFG_RX_FCS_ERROR; - if (*total & FIF_BCN_PRBRESP_PROMISC) { - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (*total & FIF_CONTROL) - wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + if (wl->state == WL1251_STATE_OFF) + goto out; - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* apply configured filters */ + wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); } /* HW encryption */ @@ -1358,7 +1362,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->filter_work, wl1251_filter_work); INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); wl->channel = WL1251_DEFAULT_CHANNEL; wl->scanning = false;