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.c116
1 files changed, 114 insertions, 2 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0793d7a8d743..d5571b9420cd 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -815,6 +815,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
815 return 0; 815 return 0;
816} 816}
817 817
818static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
819 struct net_device *dev,
820 enum nl80211_iftype type)
821{
822 struct ieee80211_sub_if_data *sdata;
823 u64 mask, start, addr, val, inc;
824 u8 *m;
825 u8 tmp_addr[ETH_ALEN];
826 int i;
827
828 /* default ... something at least */
829 memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
830
831 if (is_zero_ether_addr(local->hw.wiphy->addr_mask) &&
832 local->hw.wiphy->n_addresses <= 1)
833 return;
834
835
836 mutex_lock(&local->iflist_mtx);
837
838 switch (type) {
839 case NL80211_IFTYPE_MONITOR:
840 /* doesn't matter */
841 break;
842 case NL80211_IFTYPE_WDS:
843 case NL80211_IFTYPE_AP_VLAN:
844 /* match up with an AP interface */
845 list_for_each_entry(sdata, &local->interfaces, list) {
846 if (sdata->vif.type != NL80211_IFTYPE_AP)
847 continue;
848 memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN);
849 break;
850 }
851 /* keep default if no AP interface present */
852 break;
853 default:
854 /* assign a new address if possible -- try n_addresses first */
855 for (i = 0; i < local->hw.wiphy->n_addresses; i++) {
856 bool used = false;
857
858 list_for_each_entry(sdata, &local->interfaces, list) {
859 if (memcmp(local->hw.wiphy->addresses[i].addr,
860 sdata->vif.addr, ETH_ALEN) == 0) {
861 used = true;
862 break;
863 }
864 }
865
866 if (!used) {
867 memcpy(dev->perm_addr,
868 local->hw.wiphy->addresses[i].addr,
869 ETH_ALEN);
870 break;
871 }
872 }
873
874 /* try mask if available */
875 if (is_zero_ether_addr(local->hw.wiphy->addr_mask))
876 break;
877
878 m = local->hw.wiphy->addr_mask;
879 mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
880 ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
881 ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
882
883 if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
884 /* not a contiguous mask ... not handled now! */
885 printk(KERN_DEBUG "not contiguous\n");
886 break;
887 }
888
889 m = local->hw.wiphy->perm_addr;
890 start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
891 ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
892 ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
893
894 inc = 1ULL<<__ffs64(mask);
895 val = (start & mask);
896 addr = (start & ~mask) | (val & mask);
897 do {
898 bool used = false;
899
900 tmp_addr[5] = addr >> 0*8;
901 tmp_addr[4] = addr >> 1*8;
902 tmp_addr[3] = addr >> 2*8;
903 tmp_addr[2] = addr >> 3*8;
904 tmp_addr[1] = addr >> 4*8;
905 tmp_addr[0] = addr >> 5*8;
906
907 val += inc;
908
909 list_for_each_entry(sdata, &local->interfaces, list) {
910 if (memcmp(tmp_addr, sdata->vif.addr,
911 ETH_ALEN) == 0) {
912 used = true;
913 break;
914 }
915 }
916
917 if (!used) {
918 memcpy(dev->perm_addr, tmp_addr, ETH_ALEN);
919 break;
920 }
921 addr = (start & ~mask) | (val & mask);
922 } while (addr != start);
923
924 break;
925 }
926
927 mutex_unlock(&local->iflist_mtx);
928}
929
818int ieee80211_if_add(struct ieee80211_local *local, const char *name, 930int ieee80211_if_add(struct ieee80211_local *local, const char *name,
819 struct net_device **new_dev, enum nl80211_iftype type, 931 struct net_device **new_dev, enum nl80211_iftype type,
820 struct vif_params *params) 932 struct vif_params *params)
@@ -844,8 +956,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
844 if (ret < 0) 956 if (ret < 0)
845 goto fail; 957 goto fail;
846 958
847 memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); 959 ieee80211_assign_perm_addr(local, ndev, type);
848 memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); 960 memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
849 SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); 961 SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
850 962
851 /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ 963 /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */