diff options
author | David Gnedt <david.gnedt@davizone.at> | 2014-01-07 07:08:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-01-09 10:56:06 -0500 |
commit | 9ed74ba029fc920701cdcada8e25889a6d64a335 (patch) | |
tree | cc4a3602356342153a6fca3f49e8995de3882291 /drivers/net/wireless/ti | |
parent | 4d09b5378defd4ef685f9d33e0d35b380109eafa (diff) |
wl1251: implement multicast address filtering (fwd)
Port multicast address filtering from wl1271 driver.
It sets up the hardware multicast address filter in configure_filter() with
addresses supplied through prepare_multicast().
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ti')
-rw-r--r-- | drivers/net/wireless/ti/wl1251/acx.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl1251/acx.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl1251/init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl1251/main.c | 57 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl1251/wl1251.h | 1 |
5 files changed, 67 insertions, 11 deletions
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index b390adfb5d89..4205970494de 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c | |||
@@ -381,7 +381,8 @@ out: | |||
381 | return ret; | 381 | return ret; |
382 | } | 382 | } |
383 | 383 | ||
384 | int wl1251_acx_group_address_tbl(struct wl1251 *wl) | 384 | int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, |
385 | void *mc_list, u32 mc_list_len) | ||
385 | { | 386 | { |
386 | struct acx_dot11_grp_addr_tbl *acx; | 387 | struct acx_dot11_grp_addr_tbl *acx; |
387 | int ret; | 388 | int ret; |
@@ -393,9 +394,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl) | |||
393 | return -ENOMEM; | 394 | return -ENOMEM; |
394 | 395 | ||
395 | /* MAC filtering */ | 396 | /* MAC filtering */ |
396 | acx->enabled = 0; | 397 | acx->enabled = enable; |
397 | acx->num_groups = 0; | 398 | acx->num_groups = mc_list_len; |
398 | memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); | 399 | memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); |
399 | 400 | ||
400 | ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | 401 | ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, |
401 | acx, sizeof(*acx)); | 402 | acx, sizeof(*acx)); |
diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h index 5360bbecd073..2bdec38699f4 100644 --- a/drivers/net/wireless/ti/wl1251/acx.h +++ b/drivers/net/wireless/ti/wl1251/acx.h | |||
@@ -350,8 +350,8 @@ struct acx_slot { | |||
350 | } __packed; | 350 | } __packed; |
351 | 351 | ||
352 | 352 | ||
353 | #define ADDRESS_GROUP_MAX (8) | 353 | #define ACX_MC_ADDRESS_GROUP_MAX (8) |
354 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | 354 | #define ACX_MC_ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) |
355 | 355 | ||
356 | struct acx_dot11_grp_addr_tbl { | 356 | struct acx_dot11_grp_addr_tbl { |
357 | struct acx_header header; | 357 | struct acx_header header; |
@@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl { | |||
359 | u8 enabled; | 359 | u8 enabled; |
360 | u8 num_groups; | 360 | u8 num_groups; |
361 | u8 pad[2]; | 361 | u8 pad[2]; |
362 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | 362 | u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN]; |
363 | } __packed; | 363 | } __packed; |
364 | 364 | ||
365 | 365 | ||
@@ -1463,7 +1463,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); | |||
1463 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); | 1463 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); |
1464 | int wl1251_acx_pd_threshold(struct wl1251 *wl); | 1464 | int wl1251_acx_pd_threshold(struct wl1251 *wl); |
1465 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); | 1465 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); |
1466 | int wl1251_acx_group_address_tbl(struct wl1251 *wl); | 1466 | int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, |
1467 | void *mc_list, u32 mc_list_len); | ||
1467 | int wl1251_acx_service_period_timeout(struct wl1251 *wl); | 1468 | int wl1251_acx_service_period_timeout(struct wl1251 *wl); |
1468 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); | 1469 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); |
1469 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); | 1470 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); |
diff --git a/drivers/net/wireless/ti/wl1251/init.c b/drivers/net/wireless/ti/wl1251/init.c index 4b78965ebf6f..1d799bffaa9f 100644 --- a/drivers/net/wireless/ti/wl1251/init.c +++ b/drivers/net/wireless/ti/wl1251/init.c | |||
@@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl) | |||
127 | if (ret < 0) | 127 | if (ret < 0) |
128 | return ret; | 128 | return ret; |
129 | 129 | ||
130 | ret = wl1251_acx_group_address_tbl(wl); | 130 | ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0); |
131 | if (ret < 0) | 131 | if (ret < 0) |
132 | return ret; | 132 | return ret; |
133 | 133 | ||
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index afd79aa69869..cda38813596e 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/etherdevice.h> | 28 | #include <linux/etherdevice.h> |
29 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/netdevice.h> | ||
31 | 32 | ||
32 | #include "wl1251.h" | 33 | #include "wl1251.h" |
33 | #include "wl12xx_80211.h" | 34 | #include "wl12xx_80211.h" |
@@ -677,6 +678,44 @@ out: | |||
677 | return ret; | 678 | return ret; |
678 | } | 679 | } |
679 | 680 | ||
681 | struct wl1251_filter_params { | ||
682 | bool enabled; | ||
683 | int mc_list_length; | ||
684 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; | ||
685 | }; | ||
686 | |||
687 | static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw, | ||
688 | struct netdev_hw_addr_list *mc_list) | ||
689 | { | ||
690 | struct wl1251_filter_params *fp; | ||
691 | struct netdev_hw_addr *ha; | ||
692 | struct wl1251 *wl = hw->priv; | ||
693 | |||
694 | if (unlikely(wl->state == WL1251_STATE_OFF)) | ||
695 | return 0; | ||
696 | |||
697 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); | ||
698 | if (!fp) { | ||
699 | wl1251_error("Out of memory setting filters."); | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | /* update multicast filtering parameters */ | ||
704 | fp->mc_list_length = 0; | ||
705 | if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { | ||
706 | fp->enabled = false; | ||
707 | } else { | ||
708 | fp->enabled = true; | ||
709 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
710 | memcpy(fp->mc_list[fp->mc_list_length], | ||
711 | ha->addr, ETH_ALEN); | ||
712 | fp->mc_list_length++; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | return (u64)(unsigned long)fp; | ||
717 | } | ||
718 | |||
680 | #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | 719 | #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ |
681 | FIF_ALLMULTI | \ | 720 | FIF_ALLMULTI | \ |
682 | FIF_FCSFAIL | \ | 721 | FIF_FCSFAIL | \ |
@@ -687,8 +726,9 @@ out: | |||
687 | 726 | ||
688 | static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | 727 | static void wl1251_op_configure_filter(struct ieee80211_hw *hw, |
689 | unsigned int changed, | 728 | unsigned int changed, |
690 | unsigned int *total,u64 multicast) | 729 | unsigned int *total, u64 multicast) |
691 | { | 730 | { |
731 | struct wl1251_filter_params *fp = (void *)(unsigned long)multicast; | ||
692 | struct wl1251 *wl = hw->priv; | 732 | struct wl1251 *wl = hw->priv; |
693 | int ret; | 733 | int ret; |
694 | 734 | ||
@@ -697,9 +737,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | |||
697 | *total &= WL1251_SUPPORTED_FILTERS; | 737 | *total &= WL1251_SUPPORTED_FILTERS; |
698 | changed &= WL1251_SUPPORTED_FILTERS; | 738 | changed &= WL1251_SUPPORTED_FILTERS; |
699 | 739 | ||
700 | if (changed == 0) | 740 | if (changed == 0) { |
701 | /* no filters which we support changed */ | 741 | /* no filters which we support changed */ |
742 | kfree(fp); | ||
702 | return; | 743 | return; |
744 | } | ||
703 | 745 | ||
704 | mutex_lock(&wl->mutex); | 746 | mutex_lock(&wl->mutex); |
705 | 747 | ||
@@ -736,6 +778,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | |||
736 | if (ret < 0) | 778 | if (ret < 0) |
737 | goto out; | 779 | goto out; |
738 | 780 | ||
781 | if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS) | ||
782 | ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0); | ||
783 | else if (fp) | ||
784 | ret = wl1251_acx_group_address_tbl(wl, fp->enabled, | ||
785 | fp->mc_list, | ||
786 | fp->mc_list_length); | ||
787 | if (ret < 0) | ||
788 | goto out; | ||
789 | |||
739 | /* send filters to firmware */ | 790 | /* send filters to firmware */ |
740 | wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); | 791 | wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); |
741 | 792 | ||
@@ -743,6 +794,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | |||
743 | 794 | ||
744 | out: | 795 | out: |
745 | mutex_unlock(&wl->mutex); | 796 | mutex_unlock(&wl->mutex); |
797 | kfree(fp); | ||
746 | } | 798 | } |
747 | 799 | ||
748 | /* HW encryption */ | 800 | /* HW encryption */ |
@@ -1282,6 +1334,7 @@ static const struct ieee80211_ops wl1251_ops = { | |||
1282 | .add_interface = wl1251_op_add_interface, | 1334 | .add_interface = wl1251_op_add_interface, |
1283 | .remove_interface = wl1251_op_remove_interface, | 1335 | .remove_interface = wl1251_op_remove_interface, |
1284 | .config = wl1251_op_config, | 1336 | .config = wl1251_op_config, |
1337 | .prepare_multicast = wl1251_op_prepare_multicast, | ||
1285 | .configure_filter = wl1251_op_configure_filter, | 1338 | .configure_filter = wl1251_op_configure_filter, |
1286 | .tx = wl1251_op_tx, | 1339 | .tx = wl1251_op_tx, |
1287 | .set_key = wl1251_op_set_key, | 1340 | .set_key = wl1251_op_set_key, |
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 58bb414c51e5..e231cdc44fc5 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h | |||
@@ -93,6 +93,7 @@ enum { | |||
93 | } while (0) | 93 | } while (0) |
94 | 94 | ||
95 | #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | 95 | #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ |
96 | CFG_MC_FILTER_EN | \ | ||
96 | CFG_BSSID_FILTER_EN) | 97 | CFG_BSSID_FILTER_EN) |
97 | 98 | ||
98 | #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ | 99 | #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ |