diff options
Diffstat (limited to 'net/mac80211/iface.c')
| -rw-r--r-- | net/mac80211/iface.c | 124 |
1 files changed, 117 insertions, 7 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e08fa8eda1b3..50deb017fd6e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -413,8 +413,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 413 | 413 | ||
| 414 | netif_addr_lock_bh(dev); | 414 | netif_addr_lock_bh(dev); |
| 415 | spin_lock_bh(&local->filter_lock); | 415 | spin_lock_bh(&local->filter_lock); |
| 416 | __dev_addr_unsync(&local->mc_list, &local->mc_count, | 416 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); |
| 417 | &dev->mc_list, &dev->mc_count); | ||
| 418 | spin_unlock_bh(&local->filter_lock); | 417 | spin_unlock_bh(&local->filter_lock); |
| 419 | netif_addr_unlock_bh(dev); | 418 | netif_addr_unlock_bh(dev); |
| 420 | 419 | ||
| @@ -487,7 +486,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 487 | cancel_work_sync(&sdata->u.mgd.work); | 486 | cancel_work_sync(&sdata->u.mgd.work); |
| 488 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 487 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
| 489 | cancel_work_sync(&sdata->u.mgd.monitor_work); | 488 | cancel_work_sync(&sdata->u.mgd.monitor_work); |
| 490 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | 489 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); |
| 491 | 490 | ||
| 492 | /* | 491 | /* |
| 493 | * When we get here, the interface is marked down. | 492 | * When we get here, the interface is marked down. |
| @@ -597,8 +596,7 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
| 597 | sdata->flags ^= IEEE80211_SDATA_PROMISC; | 596 | sdata->flags ^= IEEE80211_SDATA_PROMISC; |
| 598 | } | 597 | } |
| 599 | spin_lock_bh(&local->filter_lock); | 598 | spin_lock_bh(&local->filter_lock); |
| 600 | __dev_addr_sync(&local->mc_list, &local->mc_count, | 599 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); |
| 601 | &dev->mc_list, &dev->mc_count); | ||
| 602 | spin_unlock_bh(&local->filter_lock); | 600 | spin_unlock_bh(&local->filter_lock); |
| 603 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 601 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
| 604 | } | 602 | } |
| @@ -816,6 +814,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 816 | return 0; | 814 | return 0; |
| 817 | } | 815 | } |
| 818 | 816 | ||
| 817 | static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||
| 818 | struct net_device *dev, | ||
| 819 | enum nl80211_iftype type) | ||
| 820 | { | ||
| 821 | struct ieee80211_sub_if_data *sdata; | ||
| 822 | u64 mask, start, addr, val, inc; | ||
| 823 | u8 *m; | ||
| 824 | u8 tmp_addr[ETH_ALEN]; | ||
| 825 | int i; | ||
| 826 | |||
| 827 | /* default ... something at least */ | ||
| 828 | memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | ||
| 829 | |||
| 830 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && | ||
| 831 | local->hw.wiphy->n_addresses <= 1) | ||
| 832 | return; | ||
| 833 | |||
| 834 | |||
| 835 | mutex_lock(&local->iflist_mtx); | ||
| 836 | |||
| 837 | switch (type) { | ||
| 838 | case NL80211_IFTYPE_MONITOR: | ||
| 839 | /* doesn't matter */ | ||
| 840 | break; | ||
| 841 | case NL80211_IFTYPE_WDS: | ||
| 842 | case NL80211_IFTYPE_AP_VLAN: | ||
| 843 | /* match up with an AP interface */ | ||
| 844 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 845 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
| 846 | continue; | ||
| 847 | memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); | ||
| 848 | break; | ||
| 849 | } | ||
| 850 | /* keep default if no AP interface present */ | ||
| 851 | break; | ||
| 852 | default: | ||
| 853 | /* assign a new address if possible -- try n_addresses first */ | ||
| 854 | for (i = 0; i < local->hw.wiphy->n_addresses; i++) { | ||
| 855 | bool used = false; | ||
| 856 | |||
| 857 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 858 | if (memcmp(local->hw.wiphy->addresses[i].addr, | ||
| 859 | sdata->vif.addr, ETH_ALEN) == 0) { | ||
| 860 | used = true; | ||
| 861 | break; | ||
| 862 | } | ||
| 863 | } | ||
| 864 | |||
| 865 | if (!used) { | ||
| 866 | memcpy(dev->perm_addr, | ||
| 867 | local->hw.wiphy->addresses[i].addr, | ||
| 868 | ETH_ALEN); | ||
| 869 | break; | ||
| 870 | } | ||
| 871 | } | ||
| 872 | |||
| 873 | /* try mask if available */ | ||
| 874 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) | ||
| 875 | break; | ||
| 876 | |||
| 877 | m = local->hw.wiphy->addr_mask; | ||
| 878 | mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 879 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 880 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 881 | |||
| 882 | if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { | ||
| 883 | /* not a contiguous mask ... not handled now! */ | ||
| 884 | printk(KERN_DEBUG "not contiguous\n"); | ||
| 885 | break; | ||
| 886 | } | ||
| 887 | |||
| 888 | m = local->hw.wiphy->perm_addr; | ||
| 889 | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 890 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 891 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 892 | |||
| 893 | inc = 1ULL<<__ffs64(mask); | ||
| 894 | val = (start & mask); | ||
| 895 | addr = (start & ~mask) | (val & mask); | ||
| 896 | do { | ||
| 897 | bool used = false; | ||
| 898 | |||
| 899 | tmp_addr[5] = addr >> 0*8; | ||
| 900 | tmp_addr[4] = addr >> 1*8; | ||
| 901 | tmp_addr[3] = addr >> 2*8; | ||
| 902 | tmp_addr[2] = addr >> 3*8; | ||
| 903 | tmp_addr[1] = addr >> 4*8; | ||
| 904 | tmp_addr[0] = addr >> 5*8; | ||
| 905 | |||
| 906 | val += inc; | ||
| 907 | |||
| 908 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 909 | if (memcmp(tmp_addr, sdata->vif.addr, | ||
| 910 | ETH_ALEN) == 0) { | ||
| 911 | used = true; | ||
| 912 | break; | ||
| 913 | } | ||
| 914 | } | ||
| 915 | |||
| 916 | if (!used) { | ||
| 917 | memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); | ||
| 918 | break; | ||
| 919 | } | ||
| 920 | addr = (start & ~mask) | (val & mask); | ||
| 921 | } while (addr != start); | ||
| 922 | |||
| 923 | break; | ||
| 924 | } | ||
| 925 | |||
| 926 | mutex_unlock(&local->iflist_mtx); | ||
| 927 | } | ||
| 928 | |||
| 819 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 929 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
| 820 | struct net_device **new_dev, enum nl80211_iftype type, | 930 | struct net_device **new_dev, enum nl80211_iftype type, |
| 821 | struct vif_params *params) | 931 | struct vif_params *params) |
| @@ -845,8 +955,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 845 | if (ret < 0) | 955 | if (ret < 0) |
| 846 | goto fail; | 956 | goto fail; |
| 847 | 957 | ||
| 848 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 958 | ieee80211_assign_perm_addr(local, ndev, type); |
| 849 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | 959 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); |
| 850 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 960 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
| 851 | 961 | ||
| 852 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 962 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
