diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index f1573a9c2336..00ca704ece35 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -39,6 +39,8 @@ static void housekeeping_init(struct zd_mac *mac); | |||
39 | static void housekeeping_enable(struct zd_mac *mac); | 39 | static void housekeeping_enable(struct zd_mac *mac); |
40 | static void housekeeping_disable(struct zd_mac *mac); | 40 | static void housekeeping_disable(struct zd_mac *mac); |
41 | 41 | ||
42 | static void set_multicast_hash_handler(struct work_struct *work); | ||
43 | |||
42 | int zd_mac_init(struct zd_mac *mac, | 44 | int zd_mac_init(struct zd_mac *mac, |
43 | struct net_device *netdev, | 45 | struct net_device *netdev, |
44 | struct usb_interface *intf) | 46 | struct usb_interface *intf) |
@@ -55,6 +57,7 @@ int zd_mac_init(struct zd_mac *mac, | |||
55 | softmac_init(ieee80211_priv(netdev)); | 57 | softmac_init(ieee80211_priv(netdev)); |
56 | zd_chip_init(&mac->chip, netdev, intf); | 58 | zd_chip_init(&mac->chip, netdev, intf); |
57 | housekeeping_init(mac); | 59 | housekeeping_init(mac); |
60 | INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); | ||
58 | return 0; | 61 | return 0; |
59 | } | 62 | } |
60 | 63 | ||
@@ -136,6 +139,7 @@ out: | |||
136 | 139 | ||
137 | void zd_mac_clear(struct zd_mac *mac) | 140 | void zd_mac_clear(struct zd_mac *mac) |
138 | { | 141 | { |
142 | flush_workqueue(zd_workqueue); | ||
139 | zd_chip_clear(&mac->chip); | 143 | zd_chip_clear(&mac->chip); |
140 | ZD_ASSERT(!spin_is_locked(&mac->lock)); | 144 | ZD_ASSERT(!spin_is_locked(&mac->lock)); |
141 | ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); | 145 | ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); |
@@ -256,6 +260,43 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) | |||
256 | return 0; | 260 | return 0; |
257 | } | 261 | } |
258 | 262 | ||
263 | static void set_multicast_hash_handler(struct work_struct *work) | ||
264 | { | ||
265 | struct zd_mac *mac = container_of(work, struct zd_mac, | ||
266 | set_multicast_hash_work); | ||
267 | struct zd_mc_hash hash; | ||
268 | |||
269 | spin_lock_irq(&mac->lock); | ||
270 | hash = mac->multicast_hash; | ||
271 | spin_unlock_irq(&mac->lock); | ||
272 | |||
273 | zd_chip_set_multicast_hash(&mac->chip, &hash); | ||
274 | } | ||
275 | |||
276 | void zd_mac_set_multicast_list(struct net_device *dev) | ||
277 | { | ||
278 | struct zd_mc_hash hash; | ||
279 | struct zd_mac *mac = zd_netdev_mac(dev); | ||
280 | struct dev_mc_list *mc; | ||
281 | unsigned long flags; | ||
282 | |||
283 | if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { | ||
284 | zd_mc_add_all(&hash); | ||
285 | } else { | ||
286 | zd_mc_clear(&hash); | ||
287 | for (mc = dev->mc_list; mc; mc = mc->next) { | ||
288 | dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n", | ||
289 | MAC_ARG(mc->dmi_addr)); | ||
290 | zd_mc_add_addr(&hash, mc->dmi_addr); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | spin_lock_irqsave(&mac->lock, flags); | ||
295 | mac->multicast_hash = hash; | ||
296 | spin_unlock_irqrestore(&mac->lock, flags); | ||
297 | queue_work(zd_workqueue, &mac->set_multicast_hash_work); | ||
298 | } | ||
299 | |||
259 | int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) | 300 | int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) |
260 | { | 301 | { |
261 | int r; | 302 | int r; |
@@ -618,6 +659,9 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) | |||
618 | range->we_version_compiled = WIRELESS_EXT; | 659 | range->we_version_compiled = WIRELESS_EXT; |
619 | range->we_version_source = 20; | 660 | range->we_version_source = 20; |
620 | 661 | ||
662 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
663 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
664 | |||
621 | ZD_ASSERT(!irqs_disabled()); | 665 | ZD_ASSERT(!irqs_disabled()); |
622 | spin_lock_irq(&mac->lock); | 666 | spin_lock_irq(&mac->lock); |
623 | regdomain = mac->regdomain; | 667 | regdomain = mac->regdomain; |
@@ -930,7 +974,8 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, | |||
930 | } | 974 | } |
931 | 975 | ||
932 | return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || | 976 | return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || |
933 | is_multicast_ether_addr(hdr->addr1) || | 977 | (is_multicast_ether_addr(hdr->addr1) && |
978 | memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || | ||
934 | (netdev->flags & IFF_PROMISC); | 979 | (netdev->flags & IFF_PROMISC); |
935 | } | 980 | } |
936 | 981 | ||
@@ -1062,10 +1107,8 @@ int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) | |||
1062 | memcpy(skb_put(skb, length), buffer, length); | 1107 | memcpy(skb_put(skb, length), buffer, length); |
1063 | 1108 | ||
1064 | r = ieee80211_rx(ieee, skb, &stats); | 1109 | r = ieee80211_rx(ieee, skb, &stats); |
1065 | if (!r) { | 1110 | if (!r) |
1066 | ZD_ASSERT(in_irq()); | 1111 | dev_kfree_skb_any(skb); |
1067 | dev_kfree_skb_irq(skb); | ||
1068 | } | ||
1069 | return 0; | 1112 | return 0; |
1070 | } | 1113 | } |
1071 | 1114 | ||