]> Pileus Git - ~andy/linux/commitdiff
mac80211: reject setting masked mac addresses
authorHelmut Schaa <helmut.schaa@googlemail.com>
Tue, 27 Nov 2012 17:23:06 +0000 (18:23 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 28 Nov 2012 12:52:43 +0000 (13:52 +0100)
If a driver registers an address mask we should ensure that no
interface gets an address assigned that isn't covered by the
registered address mask. This prevents invalid configurations
from reaching the device and causing problems.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
[change function flow to reduce indentation, fix locking]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/iface.c

index 5331662489f7ed30a12e62d638228f3114c4cca1..40c36d5d73775f348c53bc7f350d0ae92cf813db 100644 (file)
@@ -223,6 +223,47 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
+{
+       struct ieee80211_sub_if_data *sdata;
+       u64 new, mask, tmp;
+       u8 *m;
+       int ret = 0;
+
+       if (is_zero_ether_addr(local->hw.wiphy->addr_mask))
+               return 0;
+
+       m = addr;
+       new =   ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
+               ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
+               ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
+
+       m = local->hw.wiphy->addr_mask;
+       mask =  ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
+               ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
+               ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
+
+
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+                       continue;
+
+               m = sdata->vif.addr;
+               tmp =   ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
+                       ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
+                       ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
+
+               if ((new & ~mask) != (tmp & ~mask)) {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       mutex_unlock(&local->iflist_mtx);
+
+       return ret;
+}
+
 static int ieee80211_change_mac(struct net_device *dev, void *addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -232,6 +273,10 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
        if (ieee80211_sdata_running(sdata))
                return -EBUSY;
 
+       ret = ieee80211_verify_mac(sdata->local, sa->sa_data);
+       if (ret)
+               return ret;
+
        ret = eth_mac_addr(dev, sa);
 
        if (ret == 0)