2014-02-28 15:12:00

by Michal Kazior

[permalink] [raw]
Subject: [RFC 0/3] cfg80211/mac80211: multi-vif csa preparation

Hi,

These are some of the changes I think are
necessary for getting multi-vif and multi-chan
channel switching working.

This is based on Luca's interface combination
patchset v7.

This is taken from my local prototype. However
since Luca's patchsets are still under review
there's nothing more sane I can provide now ;-)

The patch #3 depends on my cfg80211_leave() fix.


Michal Kazior (3):
cfg80211: allow drivers to iterate over matching combinations
mac80211: add max channel calculation utility function
cfg80211: export interface stopping function

include/net/cfg80211.h | 41 ++++++++++++++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/util.c | 43 ++++++++++++++++++++++++++++++++++++++++
net/wireless/core.c | 36 +++++++++++++++++++++++++++++++---
net/wireless/core.h | 3 +++
net/wireless/trace.h | 15 ++++++++++++++
net/wireless/util.c | 49 +++++++++++++++++++++++++++++++++++++++-------
7 files changed, 178 insertions(+), 10 deletions(-)

--
1.8.5.3



2014-02-28 15:12:03

by Michal Kazior

[permalink] [raw]
Subject: [RFC 3/3] cfg80211: export interface stopping function

This exports a new cfg80211_stop_iface() function.

This is intended for driver internal interface
combination management and channel switching. This
is probably most useful for AP or provide a
unified way to stopping interface operation from a
driver.

Due to locking issues (it re-enters driver) the
call is asynchronous and uses cfg80211 even
list/worker.

Signed-off-by: Michal Kazior <[email protected]>
---
include/net/cfg80211.h | 14 ++++++++++++++
net/wireless/core.c | 36 +++++++++++++++++++++++++++++++++---
net/wireless/core.h | 3 +++
net/wireless/trace.h | 15 +++++++++++++++
net/wireless/util.c | 5 +++++
5 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f3411c9..15376c0 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4732,6 +4732,20 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
void *data),
void *data);

+/**
+ * cfg80211_stop_iface - stop operation on given interface
+ *
+ * @wiphy: the wiphy
+ * @wdev: wireless device
+ *
+ * Cease operation of the given interface as if the interface was brought down.
+ * This stops beaconing or disconnects for a BSS.
+ *
+ * This doesn't need any locks and is asynchronous. This is intended for
+ * channel switching and internal driver interface combination management.
+ */
+void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */

/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index afd0f08..b2f064f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -748,14 +748,14 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
rdev->num_running_monitor_ifaces += num;
}

-void cfg80211_leave(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev)
+void __cfg80211_leave(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
{
struct net_device *dev = wdev->netdev;

ASSERT_RTNL();
+ ASSERT_WDEV_LOCK(wdev);

- wdev_lock(wdev);
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
__cfg80211_leave_ibss(rdev, dev, true);
@@ -786,9 +786,39 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
}

wdev->beacon_interval = 0;
+}
+
+void cfg80211_leave(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ ASSERT_RTNL();
+
+ wdev_lock(wdev);
+ __cfg80211_leave(rdev, wdev);
wdev_unlock(wdev);
}

+void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ trace_cfg80211_stop_iface(wiphy, wdev);
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_STOPPED;
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ queue_work(cfg80211_wq, &rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_stop_iface);
+
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state, void *ptr)
{
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 78e6847..402a653 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -182,6 +182,7 @@ enum cfg80211_event_type {
EVENT_ROAMED,
EVENT_DISCONNECTED,
EVENT_IBSS_JOINED,
+ EVENT_STOPPED,
};

struct cfg80211_event {
@@ -439,6 +440,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);

+void __cfg80211_leave(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
void cfg80211_leave(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);

diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index aabccf1..24acf96 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2615,6 +2615,21 @@ TRACE_EVENT(cfg80211_ft_event,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
);

+TRACE_EVENT(cfg80211_stop_iface,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+ TP_ARGS(wiphy, wdev),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
+ WIPHY_PR_ARG, WDEV_PR_ARG)
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */

#undef TRACE_INCLUDE_PATH
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 486b604..2236c08 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -789,6 +789,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
unsigned long flags;
const u8 *bssid = NULL;

+ ASSERT_RTNL();
+
spin_lock_irqsave(&wdev->event_lock, flags);
while (!list_empty(&wdev->event_list)) {
ev = list_first_entry(&wdev->event_list,
@@ -823,6 +825,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
ev->ij.channel);
break;
+ case EVENT_STOPPED:
+ __cfg80211_leave(wiphy_to_dev(wdev->wiphy), wdev);
+ break;
}
wdev_unlock(wdev);

--
1.8.5.3


2014-02-28 15:12:01

by Michal Kazior

[permalink] [raw]
Subject: [RFC 2/3] mac80211: add max channel calculation utility function

The utility function has no uses yet. It is aimed
at future chanctx reservation management and
channel switching.

Signed-off-by: Michal Kazior <[email protected]>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/util.c | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d3ebe7f..508eecf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1814,6 +1814,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);

#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 955b043..7233102 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2877,3 +2877,46 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
num_different_channels,
radar_detect, num);
}
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+ void *data)
+{
+ u32 *max_num_different_channels = data;
+
+ *max_num_different_channels = max(*max_num_different_channels,
+ c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int num[NUM_NL80211_IFTYPES] = {};
+ struct ieee80211_chanctx *ctx;
+ int num_different_channels = 0;
+ u8 radar_detect = 0;
+ u32 max_num_different_channels = 1;
+ int err;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ num_different_channels++;
+
+ if (ctx->conf.radar_enabled)
+ radar_detect |= BIT(ctx->conf.def.width);
+ }
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ num[sdata->wdev.iftype]++;
+ }
+
+ err = cfg80211_iter_combinations(local->hw.wiphy,
+ num_different_channels, radar_detect,
+ num, ieee80211_iter_max_chans,
+ &max_num_different_channels);
+ if (err < 0)
+ return err;
+
+ return max_num_different_channels;
+}
--
1.8.5.3


2014-02-28 15:12:00

by Michal Kazior

[permalink] [raw]
Subject: [RFC 1/3] cfg80211: allow drivers to iterate over matching combinations

The patch splits cfg80211_check_combinations()
into an iterator function and a simple iteration
user.

This makes it possible for drivers to asses how
many channels can use given iftype setup. This in
turn can be used for future
multi-interface/multi-channel channel switching.

Signed-off-by: Michal Kazior <[email protected]>
---
include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
net/wireless/util.c | 44 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 23a72e2..f3411c9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4705,6 +4705,33 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES]);

+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ * to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ * width where radar detection is needed, as in the definition of
+ * &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ * type. The index is the interface type as specified in &enum
+ * nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+ const int num_different_channels,
+ const u8 radar_detect,
+ const int iftype_num[NUM_NL80211_IFTYPES],
+ void (*iter)(const struct ieee80211_iface_combination *c,
+ void *data),
+ void *data);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */

/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 378038d30..486b604 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1248,10 +1248,13 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
return res;
}

-int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES])
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+ const int num_different_channels,
+ const u8 radar_detect,
+ const int iftype_num[NUM_NL80211_IFTYPES],
+ void (*iter)(const struct ieee80211_iface_combination *c,
+ void *data),
+ void *data)
{
int i, j, iftype;
int num_interfaces = 0;
@@ -1307,13 +1310,40 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
- kfree(limits);
- return 0;
+
+ (*iter)(c, data);
cont:
kfree(limits);
}

- return -EBUSY;
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+ void *data)
+{
+ int *num = data;
+ (*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+ const int num_different_channels,
+ const u8 radar_detect,
+ const int iftype_num[NUM_NL80211_IFTYPES])
+{
+ int err, num = 0;
+
+ err = cfg80211_iter_combinations(wiphy, num_different_channels,
+ radar_detect, iftype_num,
+ cfg80211_iter_sum_ifcombs, &num);
+ if (err)
+ return err;
+ if (num == 0)
+ return -EBUSY;
+
+ return 0;
}
EXPORT_SYMBOL(cfg80211_check_combinations);

--
1.8.5.3