summaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2012-11-27 21:23:06 +0400
committerJohannes Berg <johannes.berg@intel.com>2012-11-28 16:52:43 +0400
commit478622e81c735ecd83d45ee6be3fd45d500aaa3b (patch)
tree631025a1b4b881e9ed179bc39d57f82b5cb13827 /net/mac80211
parent0624760c96da3ffeaec8027a016475ae752d75e1 (diff)
downloadlinux-478622e81c735ecd83d45ee6be3fd45d500aaa3b.tar.xz
mac80211: reject setting masked mac addresses
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>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/iface.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 5331662489f7..40c36d5d7377 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -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)