diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index bd1593e13f8f..1dd3f766ff49 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(void *mac_ptr); | ||
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,8 @@ 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, | ||
61 | mac); | ||
58 | return 0; | 62 | return 0; |
59 | } | 63 | } |
60 | 64 | ||
@@ -136,6 +140,7 @@ out: | |||
136 | 140 | ||
137 | void zd_mac_clear(struct zd_mac *mac) | 141 | void zd_mac_clear(struct zd_mac *mac) |
138 | { | 142 | { |
143 | flush_workqueue(zd_workqueue); | ||
139 | zd_chip_clear(&mac->chip); | 144 | zd_chip_clear(&mac->chip); |
140 | ZD_ASSERT(!spin_is_locked(&mac->lock)); | 145 | ZD_ASSERT(!spin_is_locked(&mac->lock)); |
141 | ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); | 146 | ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); |
@@ -256,6 +261,42 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) | |||
256 | return 0; | 261 | return 0; |
257 | } | 262 | } |
258 | 263 | ||
264 | static void set_multicast_hash_handler(void *mac_ptr) | ||
265 | { | ||
266 | struct zd_mac *mac = mac_ptr; | ||
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; |
@@ -930,7 +971,8 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, | |||
930 | } | 971 | } |
931 | 972 | ||
932 | return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || | 973 | return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || |
933 | is_multicast_ether_addr(hdr->addr1) || | 974 | (is_multicast_ether_addr(hdr->addr1) && |
975 | memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || | ||
934 | (netdev->flags & IFF_PROMISC); | 976 | (netdev->flags & IFF_PROMISC); |
935 | } | 977 | } |
936 | 978 | ||