diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-04-08 13:34:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-08 13:34:54 -0400 |
commit | 0f2df9eac70423838a1f8d410fd3899ddd88317b (patch) | |
tree | 0617f723320d83eca5cef9c964c001014e74213f /drivers/net/wireless/rndis_wlan.c | |
parent | 8c11e4ab09ffb975a89802dde0e9aa52a53b8aa5 (diff) | |
parent | 1144601118507f8b3b676a9a392584d216d3f2cc (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6 into merge
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-tx.c
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 267afd714c74..aceb95ef7274 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -1546,51 +1546,67 @@ static void set_multicast_list(struct usbnet *usbdev) | |||
1546 | { | 1546 | { |
1547 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1547 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
1548 | struct dev_mc_list *mclist; | 1548 | struct dev_mc_list *mclist; |
1549 | __le32 filter; | 1549 | __le32 filter, basefilter; |
1550 | int ret, i, size; | 1550 | int ret; |
1551 | char *buf; | 1551 | char *mc_addrs = NULL; |
1552 | int mc_count; | ||
1552 | 1553 | ||
1553 | filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; | 1554 | basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED | |
1555 | RNDIS_PACKET_TYPE_BROADCAST; | ||
1554 | 1556 | ||
1555 | netif_addr_lock_bh(usbdev->net); | ||
1556 | if (usbdev->net->flags & IFF_PROMISC) { | 1557 | if (usbdev->net->flags & IFF_PROMISC) { |
1557 | filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | | 1558 | filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | |
1558 | RNDIS_PACKET_TYPE_ALL_LOCAL; | 1559 | RNDIS_PACKET_TYPE_ALL_LOCAL; |
1559 | } else if (usbdev->net->flags & IFF_ALLMULTI || | 1560 | } else if (usbdev->net->flags & IFF_ALLMULTI) { |
1560 | netdev_mc_count(usbdev->net) > priv->multicast_size) { | 1561 | filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; |
1562 | } | ||
1563 | |||
1564 | if (filter != basefilter) | ||
1565 | goto set_filter; | ||
1566 | |||
1567 | /* | ||
1568 | * mc_list should be accessed holding the lock, so copy addresses to | ||
1569 | * local buffer first. | ||
1570 | */ | ||
1571 | netif_addr_lock_bh(usbdev->net); | ||
1572 | mc_count = netdev_mc_count(usbdev->net); | ||
1573 | if (mc_count > priv->multicast_size) { | ||
1561 | filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; | 1574 | filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; |
1562 | } else if (!netdev_mc_empty(usbdev->net)) { | 1575 | } else if (mc_count) { |
1563 | size = min(priv->multicast_size, netdev_mc_count(usbdev->net)); | 1576 | int i = 0; |
1564 | buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); | 1577 | |
1565 | if (!buf) { | 1578 | mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC); |
1579 | if (!mc_addrs) { | ||
1566 | netdev_warn(usbdev->net, | 1580 | netdev_warn(usbdev->net, |
1567 | "couldn't alloc %d bytes of memory\n", | 1581 | "couldn't alloc %d bytes of memory\n", |
1568 | size * ETH_ALEN); | 1582 | mc_count * ETH_ALEN); |
1569 | netif_addr_unlock_bh(usbdev->net); | 1583 | netif_addr_unlock_bh(usbdev->net); |
1570 | return; | 1584 | return; |
1571 | } | 1585 | } |
1572 | 1586 | ||
1573 | i = 0; | 1587 | netdev_for_each_mc_addr(mclist, usbdev->net) |
1574 | netdev_for_each_mc_addr(mclist, usbdev->net) { | 1588 | memcpy(mc_addrs + i++ * ETH_ALEN, |
1575 | if (i == size) | 1589 | mclist->dmi_addr, ETH_ALEN); |
1576 | break; | 1590 | } |
1577 | memcpy(buf + i++ * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); | 1591 | netif_addr_unlock_bh(usbdev->net); |
1578 | } | ||
1579 | 1592 | ||
1580 | ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf, | 1593 | if (filter != basefilter) |
1581 | i * ETH_ALEN); | 1594 | goto set_filter; |
1582 | if (ret == 0 && i > 0) | 1595 | |
1596 | if (mc_count) { | ||
1597 | ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs, | ||
1598 | mc_count * ETH_ALEN); | ||
1599 | kfree(mc_addrs); | ||
1600 | if (ret == 0) | ||
1583 | filter |= RNDIS_PACKET_TYPE_MULTICAST; | 1601 | filter |= RNDIS_PACKET_TYPE_MULTICAST; |
1584 | else | 1602 | else |
1585 | filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; | 1603 | filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; |
1586 | 1604 | ||
1587 | netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", | 1605 | netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", |
1588 | i, priv->multicast_size, ret); | 1606 | mc_count, priv->multicast_size, ret); |
1589 | |||
1590 | kfree(buf); | ||
1591 | } | 1607 | } |
1592 | netif_addr_unlock_bh(usbdev->net); | ||
1593 | 1608 | ||
1609 | set_filter: | ||
1594 | ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, | 1610 | ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, |
1595 | sizeof(filter)); | 1611 | sizeof(filter)); |
1596 | if (ret < 0) { | 1612 | if (ret < 0) { |