2012-12-10 17:57:39

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/2] mac80211: flush AP_VLAN stations when tearing down the BSS AP

Signed-off-by: Felix Fietkau <[email protected]>
---
net/mac80211/cfg.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5c61677..a5d4361 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -998,8 +998,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);

/* turn off carrier for this interface and dependent VLANs */
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ sta_info_flush(local, vlan);
netif_carrier_off(vlan->dev);
+ }
netif_carrier_off(dev);

/* remove beacon and probe response */
--
1.7.12.2



2012-12-11 19:37:24

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/2] mac80211: fix AP_VLAN channel context handling

I still don't like the lock-free stuff, I'll apply the patch below
instead.

johannes

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 53f0312..7abcf18 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -4,6 +4,7 @@

#include <linux/nl80211.h>
#include <linux/export.h>
+#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -197,6 +198,15 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)

ctx = container_of(conf, struct ieee80211_chanctx, conf);

+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan;
+
+ /* for the VLAN list */
+ ASSERT_RTNL();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
+ }
+
ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
@@ -316,6 +326,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
goto out;
}

+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan;
+
+ /* for the VLAN list */
+ ASSERT_RTNL();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
+ }
+
ieee80211_recalc_smps_chanctx(local, ctx);
out:
mutex_unlock(&local->chanctx_mtx);
@@ -331,6 +350,30 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&sdata->local->chanctx_mtx);
}

+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *ap;
+ struct ieee80211_chanctx_conf *conf;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
+ return;
+
+ ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
+
+ mutex_lock(&local->chanctx_mtx);
+
+ conf = rcu_dereference_protected(ap->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (WARN_ON(!conf))
+ goto unlock;
+
+ rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+
+ unlock:
+ mutex_unlock(&local->chanctx_mtx);
+}
+
void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 53e97dc..2f3893f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1626,6 +1626,7 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);

void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 09a80b5..b4c49d9 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -508,6 +508,7 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct ieee80211_sub_if_data *ap;
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -586,11 +587,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)

switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
- /* no need to tell driver, but set carrier */
- if (rtnl_dereference(sdata->bss->beacon))
+ /* no need to tell driver, but set carrier and chanctx */
+ if (rtnl_dereference(sdata->bss->beacon)) {
+ ieee80211_vif_vlan_copy_chanctx(sdata);
netif_carrier_on(dev);
- else
- netif_carrier_off(dev);
+ } else {
+ netif_carrier_on(dev);
+ }
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
@@ -839,6 +842,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
list_del(&sdata->u.vlan.list);
+ rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:



2012-12-11 19:44:21

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/2] mac80211: fix AP_VLAN channel context handling

On Tue, 2012-12-11 at 20:37 +0100, Johannes Berg wrote:
> I still don't like the lock-free stuff, I'll apply the patch below
> instead.

Well, modulo the bugs:


> + conf = rcu_dereference_protected(ap->vif.chanctx_conf,
> + lockdep_is_held(&local->chanctx_mtx));
> + if (WARN_ON(!conf))
> + goto unlock;

get rid of this


> - else
> - netif_carrier_off(dev);
> + } else {
> + netif_carrier_on(dev);

and don't mess up this

johannes


2012-12-11 19:49:26

by Johannes Berg

[permalink] [raw]
Subject: [PATCH] mac80211: assign VLAN channel contexts

From: Johannes Berg <[email protected]>

Make AP_VLAN type interfaces track the AP master channel
context so they have one assigned for the various lookups.
Don't give them their own refcount etc. since they're just
slaves to the AP master.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/chan.c | 38 ++++++++++++++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/iface.c | 10 +++++++---
3 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 53f0312..80e5552 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -4,6 +4,7 @@

#include <linux/nl80211.h>
#include <linux/export.h>
+#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -197,6 +198,15 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)

ctx = container_of(conf, struct ieee80211_chanctx, conf);

+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan;
+
+ /* for the VLAN list */
+ ASSERT_RTNL();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
+ }
+
ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
@@ -316,6 +326,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
goto out;
}

+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *vlan;
+
+ /* for the VLAN list */
+ ASSERT_RTNL();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
+ }
+
ieee80211_recalc_smps_chanctx(local, ctx);
out:
mutex_unlock(&local->chanctx_mtx);
@@ -331,6 +350,25 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&sdata->local->chanctx_mtx);
}

+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *ap;
+ struct ieee80211_chanctx_conf *conf;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
+ return;
+
+ ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
+
+ mutex_lock(&local->chanctx_mtx);
+
+ conf = rcu_dereference_protected(ap->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+ mutex_unlock(&local->chanctx_mtx);
+}
+
void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 53e97dc..2f3893f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1626,6 +1626,7 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);

void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 09a80b5..4a293de 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -508,6 +508,7 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct ieee80211_sub_if_data *ap;
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -586,11 +587,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)

switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
- /* no need to tell driver, but set carrier */
- if (rtnl_dereference(sdata->bss->beacon))
+ /* no need to tell driver, but set carrier and chanctx */
+ if (rtnl_dereference(sdata->bss->beacon)) {
+ ieee80211_vif_vlan_copy_chanctx(sdata);
netif_carrier_on(dev);
- else
+ } else {
netif_carrier_off(dev);
+ }
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
@@ -839,6 +842,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
list_del(&sdata->u.vlan.list);
+ rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
--
1.8.0




2012-12-10 17:57:39

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/2] mac80211: fix AP_VLAN channel context handling

When .start_ap is called, copy the channel context to all active AP VLANs.
Also copy the channel context when bringing up/down an AP VLAN if the AP
has been started already.

Signed-off-by: Felix Fietkau <[email protected]>
---
net/mac80211/cfg.c | 7 +++++++
net/mac80211/chan.c | 38 +++++++++++++++++++++++++++++++++-----
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/iface.c | 13 ++++++++++---
4 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a5d4361..da31909 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -915,6 +915,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (err)
return err;

+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ err = ieee80211_vif_copy_channel(vlan, sdata);
+ if (err)
+ return err;
+ }
+
/*
* Apply control port protocol, this allows us to
* not encrypt dynamic WEP control frames.
@@ -1001,6 +1007,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
sta_info_flush(local, vlan);
netif_carrier_off(vlan->dev);
+ ieee80211_vif_release_channel(vlan);
}
netif_carrier_off(dev);

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 53f0312..bc504f0 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -119,14 +119,17 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,

lockdep_assert_held(&local->chanctx_mtx);

- ret = drv_assign_vif_chanctx(local, sdata, ctx);
- if (ret)
- return ret;
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN) {
+ ret = drv_assign_vif_chanctx(local, sdata, ctx);
+ if (ret)
+ return ret;
+ }

rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
ctx->refcount++;

- ieee80211_recalc_txpower(sdata);
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+ ieee80211_recalc_txpower(sdata);

return 0;
}
@@ -174,7 +177,8 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
ctx->refcount--;
rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);

- drv_unassign_vif_chanctx(local, sdata, ctx);
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+ drv_unassign_vif_chanctx(local, sdata, ctx);

if (ctx->refcount > 0) {
ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
@@ -285,6 +289,30 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
}

+int ieee80211_vif_copy_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sub_if_data *parent)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
+
+ int ret;
+
+ mutex_lock(&local->chanctx_mtx);
+ conf = rcu_dereference_protected(parent->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (!conf) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ctx = container_of(conf, struct ieee80211_chanctx, conf);
+ ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+out:
+ mutex_unlock(&local->chanctx_mtx);
+ return ret;
+}
+
int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 42d0d02..d223841 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1628,6 +1628,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+int ieee80211_vif_copy_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sub_if_data *parent);

void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 40c36d5..1da2f23 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -508,6 +508,7 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct ieee80211_sub_if_data *ap_sdata;
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -587,10 +588,14 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
/* no need to tell driver, but set carrier */
- if (rtnl_dereference(sdata->bss->beacon))
- netif_carrier_on(dev);
- else
+ if (!rtnl_dereference(sdata->bss->beacon)) {
netif_carrier_off(dev);
+ break;
+ }
+
+ ap_sdata = get_bss_sdata(sdata);
+ ieee80211_vif_copy_channel(sdata, ap_sdata);
+ netif_carrier_on(dev);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
@@ -839,6 +844,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
list_del(&sdata->u.vlan.list);
+ netif_carrier_off(sdata->dev);
+ ieee80211_vif_release_channel(sdata);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
--
1.7.12.2