aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c124
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
817static 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
819int ieee80211_if_add(struct ieee80211_local *local, const char *name, 929int 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 */