aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-02-25 09:13:11 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-09 15:03:07 -0500
commitfa9029f8c34576e121a4b6ddbbd645081fe50c74 (patch)
tree0b098868b2d6f9db43c8342b2d2a1df99f3ccd3f /net/mac80211
parentdf13cce53a7b28a81460e6bfc4857e9df4956141 (diff)
mac80211: use different MAC addresses for virtual interfaces
Drivers can now advertise to cfg80211 that they have multiple MAC addresses reserved for a device, but we don't currently make use of that in mac80211. Change that and assign different addresses to new virtual interfaces (if addresses are available) in order to make it easier for users to use multiple virtual interfaces; they no longer need to always assign a new MAC address manually. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-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 */