aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_main.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2009-10-08 14:56:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:47:53 -0400
commitc87dec9f189b884df215756e285b9281cf065206 (patch)
treed8fd4ed6f27e28c0dcf5d77240e4f83cd2295129 /drivers/net/wireless/wl12xx/wl1271_main.c
parent66497dc3bd569e05a5bcb729d495eebad47aa46a (diff)
wl1271: Multicast filtering configuration
Enable multicast filtering. This way by default no multicast frames will reach the host, and when needed, only required multicast frames can be passed from the WLAN chipset to the host. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c121
1 files changed, 105 insertions, 16 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index d1042305abcc..09fe9686977a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -379,12 +379,39 @@ out:
379 return ret; 379 return ret;
380} 380}
381 381
382struct wl1271_filter_params {
383 unsigned int filters;
384 unsigned int changed;
385 int mc_list_length;
386 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
387};
388
389#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
390 FIF_ALLMULTI | \
391 FIF_FCSFAIL | \
392 FIF_BCN_PRBRESP_PROMISC | \
393 FIF_CONTROL | \
394 FIF_OTHER_BSS)
395
382static void wl1271_filter_work(struct work_struct *work) 396static void wl1271_filter_work(struct work_struct *work)
383{ 397{
384 struct wl1271 *wl = 398 struct wl1271 *wl =
385 container_of(work, struct wl1271, filter_work); 399 container_of(work, struct wl1271, filter_work);
400 struct wl1271_filter_params *fp;
401 unsigned long flags;
402 bool enabled = true;
386 int ret; 403 int ret;
387 404
405 /* first, get the filter parameters */
406 spin_lock_irqsave(&wl->wl_lock, flags);
407 fp = wl->filter_params;
408 wl->filter_params = NULL;
409 spin_unlock_irqrestore(&wl->wl_lock, flags);
410
411 if (!fp)
412 return;
413
414 /* then, lock the mutex without risk of lock-up */
388 mutex_lock(&wl->mutex); 415 mutex_lock(&wl->mutex);
389 416
390 if (wl->state == WL1271_STATE_OFF) 417 if (wl->state == WL1271_STATE_OFF)
@@ -394,6 +421,20 @@ static void wl1271_filter_work(struct work_struct *work)
394 if (ret < 0) 421 if (ret < 0)
395 goto out; 422 goto out;
396 423
424 /* configure the mc filter regardless of the changed flags */
425 if (fp->filters & FIF_ALLMULTI)
426 enabled = false;
427
428 ret = wl1271_acx_group_address_tbl(wl, enabled,
429 fp->mc_list, fp->mc_list_length);
430 if (ret < 0)
431 goto out_sleep;
432
433 /* determine, whether supported filter values have changed */
434 if (fp->changed == 0)
435 goto out;
436
437 /* apply configured filters */
397 ret = wl1271_cmd_join(wl); 438 ret = wl1271_cmd_join(wl);
398 if (ret < 0) 439 if (ret < 0)
399 goto out_sleep; 440 goto out_sleep;
@@ -403,6 +444,7 @@ out_sleep:
403 444
404out: 445out:
405 mutex_unlock(&wl->mutex); 446 mutex_unlock(&wl->mutex);
447 kfree(fp);
406} 448}
407 449
408int wl1271_plt_start(struct wl1271 *wl) 450int wl1271_plt_start(struct wl1271 *wl)
@@ -544,12 +586,20 @@ out:
544static void wl1271_op_stop(struct ieee80211_hw *hw) 586static void wl1271_op_stop(struct ieee80211_hw *hw)
545{ 587{
546 struct wl1271 *wl = hw->priv; 588 struct wl1271 *wl = hw->priv;
589 unsigned long flags;
547 int i; 590 int i;
548 591
549 wl1271_info("down"); 592 wl1271_info("down");
550 593
551 wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); 594 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
552 595
596 /* complete/cancel ongoing work */
597 cancel_work_sync(&wl->filter_work);
598 spin_lock_irqsave(&wl->wl_lock, flags);
599 kfree(wl->filter_params);
600 wl->filter_params = NULL;
601 spin_unlock_irqrestore(&wl->wl_lock, flags);
602
553 mutex_lock(&wl->mutex); 603 mutex_lock(&wl->mutex);
554 604
555 WARN_ON(wl->state != WL1271_STATE_ON); 605 WARN_ON(wl->state != WL1271_STATE_ON);
@@ -784,16 +834,52 @@ out:
784 return ret; 834 return ret;
785} 835}
786 836
787#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ 837static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
788 FIF_ALLMULTI | \ 838 struct dev_addr_list *mc_list)
789 FIF_FCSFAIL | \ 839{
790 FIF_BCN_PRBRESP_PROMISC | \ 840 struct wl1271 *wl = hw->priv;
791 FIF_CONTROL | \ 841 struct wl1271_filter_params *fp;
792 FIF_OTHER_BSS) 842 unsigned long flags;
843 int i;
844
845 /*
846 * FIXME: we should return a hash that will be passed to
847 * configure_filter() instead of saving everything in the context.
848 */
849
850 fp = kzalloc(sizeof(*fp), GFP_KERNEL);
851 if (!fp) {
852 wl1271_error("Out of memory setting filters.");
853 return 0;
854 }
855
856 /* update multicast filtering parameters */
857 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
858 mc_count = 0;
859 fp->filters |= FIF_ALLMULTI;
860 }
861
862 fp->mc_list_length = 0;
863 for (i = 0; i < mc_count; i++) {
864 if (mc_list->da_addrlen == ETH_ALEN) {
865 memcpy(fp->mc_list[fp->mc_list_length],
866 mc_list->da_addr, ETH_ALEN);
867 fp->mc_list_length++;
868 } else
869 wl1271_warning("Unknown mc address length.");
870 }
871
872 spin_lock_irqsave(&wl->wl_lock, flags);
873 kfree(wl->filter_params);
874 wl->filter_params = fp;
875 spin_unlock_irqrestore(&wl->wl_lock, flags);
876
877 return 1;
878}
793 879
794static void wl1271_op_configure_filter(struct ieee80211_hw *hw, 880static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
795 unsigned int changed, 881 unsigned int changed,
796 unsigned int *total,u64 multicast) 882 unsigned int *total, u64 multicast)
797{ 883{
798 struct wl1271 *wl = hw->priv; 884 struct wl1271 *wl = hw->priv;
799 885
@@ -802,19 +888,21 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
802 *total &= WL1271_SUPPORTED_FILTERS; 888 *total &= WL1271_SUPPORTED_FILTERS;
803 changed &= WL1271_SUPPORTED_FILTERS; 889 changed &= WL1271_SUPPORTED_FILTERS;
804 890
805 if (changed == 0) 891 if (!multicast)
806 return; 892 return;
807 893
808 /* FIXME: wl->rx_config and wl->rx_filter are not protected */
809 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
810 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
811
812 /* 894 /*
813 * FIXME: workqueues need to be properly cancelled on stop(), for 895 * FIXME: for now we are still using a workqueue for filter
814 * now let's just disable changing the filter settings. They will 896 * configuration, but with the new mac80211, this is not needed,
815 * be updated any on config(). 897 * since configure_filter can now sleep. We now have
898 * prepare_multicast, which needs to be atomic instead.
816 */ 899 */
817 /* schedule_work(&wl->filter_work); */ 900
901 /* store current filter config */
902 wl->filter_params->filters = *total;
903 wl->filter_params->changed = changed;
904
905 ieee80211_queue_work(wl->hw, &wl->filter_work);
818} 906}
819 907
820static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 908static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -1177,6 +1265,7 @@ static const struct ieee80211_ops wl1271_ops = {
1177 .remove_interface = wl1271_op_remove_interface, 1265 .remove_interface = wl1271_op_remove_interface,
1178 .config = wl1271_op_config, 1266 .config = wl1271_op_config,
1179/* .config_interface = wl1271_op_config_interface, */ 1267/* .config_interface = wl1271_op_config_interface, */
1268 .prepare_multicast = wl1271_op_prepare_multicast,
1180 .configure_filter = wl1271_op_configure_filter, 1269 .configure_filter = wl1271_op_configure_filter,
1181 .tx = wl1271_op_tx, 1270 .tx = wl1271_op_tx,
1182 .set_key = wl1271_op_set_key, 1271 .set_key = wl1271_op_set_key,