From 2b436312f0919c05804fed5aa4b7f255db196e7a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 May 2013 21:04:38 +0200 Subject: mac80211: fix queue handling crash The code I added in "mac80211: don't start new netdev queues if driver stopped" crashes for monitor and AP VLAN interfaces because while they have a netdev, they don't have queues set up by the driver. To fix the crash, exclude these from queue accounting here and just start their netdev queues unconditionally. For monitor, this is the best we can do, as we can redirect frames there to any other interface and don't know which one that will since it can be different for each frame. For AP VLAN interfaces, we can do better later and actually properly track the queue status. Not doing this is really a separate bug though. Reported-by: Ilan Peer Reported-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/mac80211/iface.c') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 60f1ce5e5e52..68f51c3af49f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -653,7 +653,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) ieee80211_recalc_ps(local, -1); - if (dev) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + /* XXX: for AP_VLAN, actually track AP queues */ + netif_tx_start_all_queues(dev); + } else if (dev) { unsigned long flags; int n_acs = IEEE80211_NUM_ACS; int ac; -- cgit v1.2.2 From 1351c5d3b189a487fbacd5cdf2dc3e6faf12c682 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 May 2013 23:09:56 +0200 Subject: mac80211: assign AP_VLAN hw queues correctly A lot of code in mac80211 assumes that the hw queues are set up correctly for all interfaces (except for monitor) but this isn't true for AP_VLAN interfaces. Fix this by copying the AP master configuration when an AP VLAN is brought up, after this the AP interface can't change its configuration any more and needs to be brought down to change it, which also forces AP_VLAN interfaces down, so just copying in open() is sufficient. Reported-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211/iface.c') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 68f51c3af49f..00e2238355f0 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -474,6 +474,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) master->control_port_protocol; sdata->control_port_no_encrypt = master->control_port_no_encrypt; + sdata->vif.cab_queue = master->vif.cab_queue; + memcpy(sdata->vif.hw_queue, master->vif.hw_queue, + sizeof(sdata->vif.hw_queue)); break; } case NL80211_IFTYPE_AP: -- cgit v1.2.2 From c8aa22db0112f640ac6631347f850879c621840b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 May 2013 01:06:09 +0200 Subject: mac80211: close AP_VLAN interfaces before unregistering all Since Eric's commit efe117ab8 ("Speedup ieee80211_remove_interfaces") there's a bug in mac80211 when it unregisters with AP_VLAN interfaces up. If the AP_VLAN interface was registered after the AP it belongs to (which is the typical case) and then we get into this code path, unregister_netdevice_many() will crash because it isn't prepared to deal with interfaces being closed in the middle of it. Exactly this happens though, because we iterate the list, find the AP master this AP_VLAN belongs to and dev_close() the dependent VLANs. After this, unregister_netdevice_many() won't pick up the fact that the AP_VLAN is already down and will do it again, causing a crash. Cc: stable@vger.kernel.org [2.6.33+] Cc: Eric Dumazet Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net/mac80211/iface.c') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 00e2238355f0..ceef64426a8d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1703,6 +1703,15 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) ASSERT_RTNL(); + /* + * Close all AP_VLAN interfaces first, as otherwise they + * might be closed while the AP interface they belong to + * is closed, causing unregister_netdevice_many() to crash. + */ + list_for_each_entry(sdata, &local->interfaces, list) + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + dev_close(sdata->dev); + mutex_lock(&local->iflist_mtx); list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_del(&sdata->list); -- cgit v1.2.2 From ac20976dcaeea3e77e40e9aac8f3799d2a22ea2b Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 27 May 2013 10:43:09 +0200 Subject: mac80211: Allow single vif mac address change with addr_mask When changing the MAC address of a single vif mac80211 will check if the new address fits into the address mask specified by the driver. This only needs to be done when using multiple BSSIDs. Hence, check the new address only against all other vifs. Also fix the MAC address assignment on new interfaces if the user changed the address of a vif such that perm_addr is not covered by addr_mask anymore. Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=57371 Signed-off-by: Helmut Schaa Signed-off-by: Jakub Kicinski Reported-by: Alessandro Lannocca Cc: Alessandro Lannocca Cc: Bruno Randolf Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'net/mac80211/iface.c') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ceef64426a8d..98d20c0f6fed 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -159,9 +159,10 @@ 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) +static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *iter; u64 new, mask, tmp; u8 *m; int ret = 0; @@ -181,11 +182,14 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + list_for_each_entry(iter, &local->interfaces, list) { + if (iter == sdata) continue; - m = sdata->vif.addr; + if (iter->vif.type == NL80211_IFTYPE_MONITOR) + continue; + + m = iter->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); @@ -209,7 +213,7 @@ 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); + ret = ieee80211_verify_mac(sdata, sa->sa_data); if (ret) return ret; @@ -1486,7 +1490,17 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, break; } + /* + * Pick address of existing interface in case user changed + * MAC address manually, default to perm_addr. + */ m = local->hw.wiphy->perm_addr; + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + continue; + m = sdata->vif.addr; + break; + } start = ((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); -- cgit v1.2.2