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 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
816static 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
818int ieee80211_if_add(struct ieee80211_local *local, const char *name, 928int 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 */