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