From d01a1e658606a0a69100f49c2ef09aacaf74d3e7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Jun 2012 14:37:16 +0200 Subject: [PATCH 01/38] mac80211: introduce channel context skeleton code Channel context are the foundation for multi-channel operation. They are are immutable and are re-created (or re-used if other interfaces are bound to a certain channel and a compatible channel type) on channel switching. This is an initial implementation and more features will come in separate patches. Signed-off-by: Michal Kazior [some changes including RCU protection] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 36 +++++++++ net/mac80211/chan.c | 147 +++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 35 +++++++++ net/mac80211/main.c | 3 + 4 files changed, 221 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 82558c8decf8..ab1b5bafb568 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -143,6 +143,32 @@ struct ieee80211_low_level_stats { unsigned int dot11RTSSuccessCount; }; +/** + * enum ieee80211_chanctx_change - change flag for channel context + * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed + */ +enum ieee80211_chanctx_change { + IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE = BIT(0), +}; + +/** + * struct ieee80211_chanctx_conf - channel context that vifs may be tuned to + * + * This is the driver-visible part. The ieee80211_chanctx + * that contains it is visible in mac80211 only. + * + * @channel: the channel to tune to + * @channel_type: the channel (HT) type + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *), size is determined in hw information. + */ +struct ieee80211_chanctx_conf { + struct ieee80211_channel *channel; + enum nl80211_channel_type channel_type; + + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + /** * enum ieee80211_bss_change - BSS change notification flags * @@ -931,6 +957,11 @@ enum ieee80211_vif_flags { * at runtime, mac80211 will never touch this field * @hw_queue: hardware queue for each AC * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only + * @chanctx_conf: The channel context this interface is assigned to, or %NULL + * when it is not assigned. This pointer is RCU-protected due to the TX + * path needing to access it; even though the netdev carrier will always + * be off when it is %NULL there can still be races and packets could be + * processed after it switches back to %NULL. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *). */ @@ -943,6 +974,8 @@ struct ieee80211_vif { u8 cab_queue; u8 hw_queue[IEEE80211_NUM_ACS]; + struct ieee80211_chanctx_conf __rcu *chanctx_conf; + u32 driver_flags; /* must be last */ @@ -1325,6 +1358,8 @@ enum ieee80211_hw_flags { * within &struct ieee80211_vif. * @sta_data_size: size (in bytes) of the drv_priv data area * within &struct ieee80211_sta. + * @chanctx_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_chanctx_conf. * * @max_rates: maximum number of alternate rate retry stages the hw * can handle. @@ -1369,6 +1404,7 @@ struct ieee80211_hw { int channel_change_time; int vif_data_size; int sta_data_size; + int chanctx_data_size; int napi_weight; u16 queues; u16 max_listen_interval; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 0bfc914ddd15..4ae94860a161 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -168,3 +168,150 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, return true; } + +static struct ieee80211_chanctx * +ieee80211_find_chanctx(struct ieee80211_local *local, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_chanctx *ctx; + + lockdep_assert_held(&local->chanctx_mtx); + + if (mode == IEEE80211_CHANCTX_EXCLUSIVE) + return NULL; + if (WARN_ON(!channel)) + return NULL; + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) + continue; + if (ctx->conf.channel != channel) + continue; + if (ctx->conf.channel_type != channel_type) + continue; + + return ctx; + } + + return NULL; +} + +static struct ieee80211_chanctx * +ieee80211_new_chanctx(struct ieee80211_local *local, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_chanctx *ctx; + + lockdep_assert_held(&local->chanctx_mtx); + + ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->conf.channel = channel; + ctx->conf.channel_type = channel_type; + ctx->mode = mode; + + list_add(&ctx->list, &local->chanctx_list); + + return ctx; +} + +static void ieee80211_free_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + lockdep_assert_held(&local->chanctx_mtx); + + WARN_ON_ONCE(ctx->refcount != 0); + + list_del(&ctx->list); + kfree_rcu(ctx, rcu_head); +} + +static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_local *local __maybe_unused = sdata->local; + + lockdep_assert_held(&local->chanctx_mtx); + + rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); + ctx->refcount++; + + return 0; +} + +static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_local *local __maybe_unused = sdata->local; + + lockdep_assert_held(&local->chanctx_mtx); + + ctx->refcount--; + rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); +} + +static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + struct ieee80211_chanctx *ctx; + + lockdep_assert_held(&local->chanctx_mtx); + + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) + return; + + ctx = container_of(conf, struct ieee80211_chanctx, conf); + + ieee80211_unassign_vif_chanctx(sdata, ctx); + if (ctx->refcount == 0) + ieee80211_free_chanctx(local, ctx); +} + +int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + enum ieee80211_chanctx_mode mode) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx *ctx; + int ret; + + mutex_lock(&local->chanctx_mtx); + __ieee80211_vif_release_channel(sdata); + + ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); + if (!ctx) + ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); + goto out; + } + + ret = ieee80211_assign_vif_chanctx(sdata, ctx); + if (ret) { + /* if assign fails refcount stays the same */ + if (ctx->refcount == 0) + ieee80211_free_chanctx(local, ctx); + goto out; + } + + out: + mutex_unlock(&local->chanctx_mtx); + return ret; +} + +void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +{ + mutex_lock(&sdata->local->chanctx_mtx); + __ieee80211_vif_release_channel(sdata); + mutex_unlock(&sdata->local->chanctx_mtx); +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8c804550465b..9a058e58d53e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -658,6 +658,30 @@ enum ieee80211_sdata_state_bits { SDATA_STATE_OFFCHANNEL, }; +/** + * enum ieee80211_chanctx_mode - channel context configuration mode + * + * @IEEE80211_CHANCTX_SHARED: channel context may be used by + * multiple interfaces + * @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used + * only by a single interface. This can be used for example for + * non-fixed channel IBSS. + */ +enum ieee80211_chanctx_mode { + IEEE80211_CHANCTX_SHARED, + IEEE80211_CHANCTX_EXCLUSIVE +}; + +struct ieee80211_chanctx { + struct list_head list; + struct rcu_head rcu_head; + + enum ieee80211_chanctx_mode mode; + int refcount; + + struct ieee80211_chanctx_conf conf; +}; + struct ieee80211_sub_if_data { struct list_head list; @@ -987,6 +1011,10 @@ struct ieee80211_local { struct ieee80211_channel *tmp_channel; enum nl80211_channel_type tmp_channel_type; + /* channel contexts */ + struct list_head chanctx_list; + struct mutex chanctx_mtx; + /* SNMP counters */ /* dot11CountersTable */ u32 dot11TransmittedFragmentCount; @@ -1510,6 +1538,13 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, enum nl80211_channel_type ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); +int __must_check +ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + enum ieee80211_chanctx_mode mode); +void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c80c4490351c..9be3ef1d2e86 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -626,6 +626,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, spin_lock_init(&local->filter_lock); spin_lock_init(&local->queue_stop_reason_lock); + INIT_LIST_HEAD(&local->chanctx_list); + mutex_init(&local->chanctx_mtx); + /* * The rx_skb_queue is only accessed from tasklets, * but other SKB queues are used from within IRQ From c3645eac479d9aaac9f8099c94bf681dc695dd34 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Jun 2012 14:37:17 +0200 Subject: [PATCH 02/38] mac80211: introduce new ieee80211_ops Introduce channel context driver methods. The channel on a context channel is immutable, but the channel type and other properties can change. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- include/net/mac80211.h | 24 +++++++++ net/mac80211/driver-ops.h | 65 +++++++++++++++++++++++ net/mac80211/trace.h | 107 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ab1b5bafb568..d9d2119f0828 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2353,6 +2353,16 @@ enum ieee80211_rate_control_changed { * The callback will be called before each transmission and upon return * mac80211 will transmit the frame right away. * The callback is optional and can (should!) sleep. + * + * @add_chanctx: Notifies device driver about new channel context creation. + * @remove_chanctx: Notifies device driver about channel context destruction. + * @change_chanctx: Notifies device driver about channel context changes that + * may happen when combining different virtual interfaces on the same + * channel context with different settings + * @assign_vif_chanctx: Notifies device driver about channel context being bound + * to vif. Possible use is for hw queue remapping. + * @unassign_vif_chanctx: Notifies device driver about channel context being + * unbound from vif. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -2497,6 +2507,20 @@ struct ieee80211_ops { void (*mgd_prepare_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + + int (*add_chanctx)(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); + void (*remove_chanctx)(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); + void (*change_chanctx)(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed); + int (*assign_vif_chanctx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx); + void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index da9003b20004..77407b31e1ff 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -871,4 +871,69 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); trace_drv_return_void(local); } + +static inline int drv_add_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + int ret = -EOPNOTSUPP; + + trace_drv_add_chanctx(local, ctx); + if (local->ops->add_chanctx) + ret = local->ops->add_chanctx(&local->hw, &ctx->conf); + trace_drv_return_int(local, ret); + + return ret; +} + +static inline void drv_remove_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + trace_drv_remove_chanctx(local, ctx); + if (local->ops->remove_chanctx) + local->ops->remove_chanctx(&local->hw, &ctx->conf); + trace_drv_return_void(local); +} + +static inline void drv_change_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + u32 changed) +{ + trace_drv_change_chanctx(local, ctx, changed); + if (local->ops->change_chanctx) + local->ops->change_chanctx(&local->hw, &ctx->conf, changed); + trace_drv_return_void(local); +} + +static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx) +{ + int ret = 0; + + check_sdata_in_driver(sdata); + + trace_drv_assign_vif_chanctx(local, sdata, ctx); + if (local->ops->assign_vif_chanctx) + ret = local->ops->assign_vif_chanctx(&local->hw, + &sdata->vif, + &ctx->conf); + trace_drv_return_int(local, ret); + + return ret; +} + +static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx) +{ + check_sdata_in_driver(sdata); + + trace_drv_unassign_vif_chanctx(local, sdata, ctx); + if (local->ops->unassign_vif_chanctx) + local->ops->unassign_vif_chanctx(&local->hw, + &sdata->vif, + &ctx->conf); + trace_drv_return_void(local); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 18d9c8a52e9e..a3f5fe2a84a8 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -28,6 +28,15 @@ #define VIF_PR_FMT " vif:%s(%d%s)" #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" +#define CHANCTX_ENTRY __field(int, freq) \ + __field(int, chantype) +#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \ + __entry->chantype = ctx->conf.channel_type +#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d" +#define CHANCTX_PR_ARG __entry->freq, __entry->chantype + + + /* * Tracing for driver callbacks. */ @@ -1256,6 +1265,104 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, TP_ARGS(local, sdata) ); +DECLARE_EVENT_CLASS(local_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx), + + TP_ARGS(local, ctx), + + TP_STRUCT__entry( + LOCAL_ENTRY + CHANCTX_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + CHANCTX_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT CHANCTX_PR_FMT, + LOCAL_PR_ARG, CHANCTX_PR_ARG + ) +); + +DEFINE_EVENT(local_chanctx, drv_add_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx), + TP_ARGS(local, ctx) +); + +DEFINE_EVENT(local_chanctx, drv_remove_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx), + TP_ARGS(local, ctx) +); + +TRACE_EVENT(drv_change_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + u32 changed), + + TP_ARGS(local, ctx, changed), + + TP_STRUCT__entry( + LOCAL_ENTRY + CHANCTX_ENTRY + __field(u32, changed) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + CHANCTX_ASSIGN; + __entry->changed = changed; + ), + + TP_printk( + LOCAL_PR_FMT CHANCTX_PR_FMT " changed:%#x", + LOCAL_PR_ARG, CHANCTX_PR_ARG, __entry->changed + ) +); + +DECLARE_EVENT_CLASS(local_sdata_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx), + + TP_ARGS(local, sdata, ctx), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + CHANCTX_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + CHANCTX_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG + ) +); + +DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx), + TP_ARGS(local, sdata, ctx) +); + +DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx *ctx), + TP_ARGS(local, sdata, ctx) +); + /* * Tracing for API calls that drivers call. */ From 35f2fce9a4376f89f2ebac705a2742ffc058f988 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Jun 2012 14:37:20 +0200 Subject: [PATCH 03/38] mac80211: use channel context notifications Channel context pointer will be accessible on both assign and unassign events. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4ae94860a161..ff3b29ec396a 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -5,6 +5,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" static enum ieee80211_chan_mode __ieee80211_get_channel_mode(struct ieee80211_local *local, @@ -205,6 +206,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; + int err; lockdep_assert_held(&local->chanctx_mtx); @@ -216,6 +218,12 @@ ieee80211_new_chanctx(struct ieee80211_local *local, ctx->conf.channel_type = channel_type; ctx->mode = mode; + err = drv_add_chanctx(local, ctx); + if (err) { + kfree(ctx); + return ERR_PTR(err); + } + list_add(&ctx->list, &local->chanctx_list); return ctx; @@ -228,6 +236,8 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, WARN_ON_ONCE(ctx->refcount != 0); + drv_remove_chanctx(local, ctx); + list_del(&ctx->list); kfree_rcu(ctx, rcu_head); } @@ -235,10 +245,15 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx *ctx) { - struct ieee80211_local *local __maybe_unused = sdata->local; + struct ieee80211_local *local = sdata->local; + int ret; lockdep_assert_held(&local->chanctx_mtx); + ret = drv_assign_vif_chanctx(local, sdata, ctx); + if (ret) + return ret; + rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); ctx->refcount++; @@ -248,12 +263,14 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx *ctx) { - struct ieee80211_local *local __maybe_unused = sdata->local; + struct ieee80211_local *local = sdata->local; lockdep_assert_held(&local->chanctx_mtx); ctx->refcount--; rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); + + drv_unassign_vif_chanctx(local, sdata, ctx); } static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) From e89a96f5cc4c39c268c771f52d675e15e3ba8123 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Jun 2012 14:37:22 +0200 Subject: [PATCH 04/38] mac80211: reuse channels for channel contexts Reuse channels with compatible channel types. Some channel types are compatible and can be used concurrently. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 59 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index ff3b29ec396a..1a8dee42e546 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -167,7 +167,17 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, sdata->vif.bss_conf.channel_type = chantype; return true; +} + +static void ieee80211_change_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + enum nl80211_channel_type chantype) +{ + if (chantype == ctx->conf.channel_type) + return; + ctx->conf.channel_type = chantype; + drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); } static struct ieee80211_chanctx * @@ -177,6 +187,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; + enum nl80211_channel_type compat_type; lockdep_assert_held(&local->chanctx_mtx); @@ -186,13 +197,19 @@ ieee80211_find_chanctx(struct ieee80211_local *local, return NULL; list_for_each_entry(ctx, &local->chanctx_list, list) { + compat_type = ctx->conf.channel_type; + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; if (ctx->conf.channel != channel) continue; - if (ctx->conf.channel_type != channel_type) + if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, + channel_type, + &compat_type)) continue; + ieee80211_change_chantype(local, ctx, compat_type); + return ctx; } @@ -260,6 +277,43 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, return 0; } +static enum nl80211_channel_type +ieee80211_calc_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_chanctx_conf *conf = &ctx->conf; + struct ieee80211_sub_if_data *sdata; + enum nl80211_channel_type result = NL80211_CHAN_NO_HT; + + lockdep_assert_held(&local->chanctx_mtx); + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) + continue; + if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + continue; + + WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( + sdata->vif.bss_conf.channel_type, + result, &result)); + } + rcu_read_unlock(); + + return result; +} + +static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + enum nl80211_channel_type chantype; + + lockdep_assert_held(&local->chanctx_mtx); + + chantype = ieee80211_calc_chantype(local, ctx); + ieee80211_change_chantype(local, ctx, chantype); +} + static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx *ctx) { @@ -271,6 +325,9 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); drv_unassign_vif_chanctx(local, sdata, ctx); + + if (ctx->refcount > 0) + ieee80211_recalc_chanctx_chantype(sdata->local, ctx); } static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) From e269d8600a8f6a9f2387b3f283bfb579a5479dc3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:46:32 +0200 Subject: [PATCH 05/38] mac80211: check channel context methods Verify that the channel context methods are all assigned by the driver or not used. Signed-off-by: Johannes Berg --- net/mac80211/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9be3ef1d2e86..d709a5d42f69 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -549,6 +549,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) return NULL; + /* check all or no channel context operations exist */ + i = !!ops->add_chanctx + !!ops->remove_chanctx + + !!ops->change_chanctx + !!ops->assign_vif_chanctx + + !!ops->unassign_vif_chanctx; + if (WARN_ON(i != 0 && i != 5)) + return NULL; + /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data From fe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:55:08 +0200 Subject: [PATCH 06/38] mac80211: track whether to use channel contexts Depending on the driver, channel contexts may be used or not. If they are used, the driver must have support for hardware scan and remain-on-channel; otherwise the driver must not advertise support for multiple channels. Also prohibit WDS type interfaces when channel contexts are to be used as there's no clear definition of which channel they use. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 +++ net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/main.c | 22 ++++++++++++++++++++++ net/mac80211/offchannel.c | 6 ++++++ net/mac80211/scan.c | 4 ++++ 5 files changed, 37 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 05f3a313db88..70a5d262815f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2189,6 +2189,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, lockdep_assert_held(&local->mtx); + if (local->use_chanctx && !local->ops->remain_on_channel) + return -EOPNOTSUPP; + roc = kzalloc(sizeof(*roc), GFP_KERNEL); if (!roc) return -ENOMEM; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9a058e58d53e..8fa00adcb8c0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -882,6 +882,8 @@ struct ieee80211_local { bool wiphy_ciphers_allocated; + bool use_chanctx; + /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d709a5d42f69..0dd1ea241c54 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -540,6 +540,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, struct ieee80211_local *local; int priv_size, i; struct wiphy *wiphy; + bool use_chanctx; if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || !ops->add_interface || !ops->remove_interface || @@ -555,6 +556,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, !!ops->unassign_vif_chanctx; if (WARN_ON(i != 0 && i != 5)) return NULL; + use_chanctx = i == 5; /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for @@ -606,6 +608,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); local->ops = ops; + local->use_chanctx = use_chanctx; /* set up some defaults */ local->hw.queues = 1; @@ -729,6 +732,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) return -EINVAL; + if (!local->use_chanctx) { + for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *comb; + + comb = &local->hw.wiphy->iface_combinations[i]; + + if (comb->num_different_channels > 1) + return -EINVAL; + } + + /* + * WDS is currently prohibited when channel contexts are used + * because there's no clear definition of which channel WDS + * type interfaces use + */ + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) + return -EINVAL; + } + /* Only HW csum features are currently compatible with mac80211 */ feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM; diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 83608ac16780..9c52fc4a045e 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, { struct ieee80211_sub_if_data *sdata; + if (WARN_ON(local->use_chanctx)) + return; + /* * notify the AP about us leaving the channel and stop all * STA interfaces. @@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, { struct ieee80211_sub_if_data *sdata; + if (WARN_ON(local->use_chanctx)) + return; + mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c4cdbde24fd3..fdaa505dab45 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -336,6 +336,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed); static int ieee80211_start_sw_scan(struct ieee80211_local *local) { + /* Software scan is not supported in multi-channel cases */ + if (local->use_chanctx) + return -EOPNOTSUPP; + /* * Hardware/driver doesn't support hw_scan, so use software * scanning instead. First send a nullfunc frame with power save From 55de908ab292c03f1eb280f51170ddb9c6b57e31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 17:24:39 +0200 Subject: [PATCH 07/38] mac80211: use channel contexts Instead of operating on a single channel only, use the new channel context infrastructure in all mac80211 code. This enables drivers that want to use the new channel context infrastructure to use multiple channels, while nothing should change for all the other drivers that don't support it. Right now this disables both TX power settings and spatial multiplexing powersave. Both need to be re-enabled on a channel context basis. Additionally, when channel contexts are used drop the connection when channel switch is received rather than trying to handle it. This will have to be improved later. [With fixes from Eliad and Emmanuel incorporated] Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 248 +++++++++++++++++++------------------ net/mac80211/chan.c | 152 ++++------------------- net/mac80211/ibss.c | 70 +++++------ net/mac80211/ieee80211_i.h | 74 ++++++++--- net/mac80211/iface.c | 28 ++--- net/mac80211/main.c | 43 ++++--- net/mac80211/mesh.c | 41 ++++-- net/mac80211/mesh_plink.c | 10 +- net/mac80211/mlme.c | 129 ++++++++++++------- net/mac80211/offchannel.c | 3 +- net/mac80211/pm.c | 2 + net/mac80211/rate.h | 12 +- net/mac80211/scan.c | 4 +- net/mac80211/sta_info.c | 12 +- net/mac80211/tx.c | 183 +++++++++++++++++---------- net/mac80211/util.c | 41 +++++- 16 files changed, 586 insertions(+), 466 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 70a5d262815f..09c90627fd19 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -372,10 +372,11 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) { + enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata); + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { struct ieee80211_supported_band *sband; - sband = sta->local->hw.wiphy->bands[ - sta->local->oper_channel->band]; + sband = sta->local->hw.wiphy->bands[band]; rate->legacy = sband->bitrates[idx].bitrate; } else rate->mcs = idx; @@ -532,6 +533,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, u64 *data) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *channel; struct sta_info *sta; struct ieee80211_local *local = sdata->local; struct station_info sinfo; @@ -607,19 +610,26 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, do_survey: i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; /* Get survey stats for current channel */ - q = 0; - while (true) { - survey.filled = 0; - if (drv_get_survey(local, q, &survey) != 0) { - survey.filled = 0; - break; - } + survey.filled = 0; - if (survey.channel && - (local->oper_channel->center_freq == - survey.channel->center_freq)) - break; - q++; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (chanctx_conf) + channel = chanctx_conf->channel; + else + channel = NULL; + rcu_read_unlock(); + + if (channel) { + q = 0; + do { + survey.filled = 0; + if (drv_get_survey(local, q, &survey) != 0) { + survey.filled = 0; + break; + } + q++; + } while (channel != survey.channel); } if (survey.filled) @@ -724,47 +734,42 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int ieee80211_set_channel(struct wiphy *wiphy, - struct net_device *netdev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +static int ieee80211_set_monitor_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_sub_if_data *sdata = NULL; - - if (netdev) - sdata = IEEE80211_DEV_TO_SUB_IF(netdev); - - switch (ieee80211_get_channel_mode(local, NULL)) { - case CHAN_MODE_HOPPING: - return -EBUSY; - case CHAN_MODE_FIXED: - if (local->oper_channel != chan || - (!sdata && local->_oper_channel_type != channel_type)) - return -EBUSY; - if (!sdata && local->_oper_channel_type == channel_type) - return 0; - break; - case CHAN_MODE_UNDEFINED: - break; - } - - if (!ieee80211_set_channel_type(local, sdata, channel_type)) - return -EBUSY; + struct ieee80211_sub_if_data *sdata; + int ret = 0; - local->oper_channel = chan; + if (local->monitor_channel == chan && + local->monitor_channel_type == channel_type) + return 0; - /* auto-detects changes */ - ieee80211_hw_config(local, 0); + mutex_lock(&local->iflist_mtx); + if (local->use_chanctx) { + sdata = rcu_dereference_protected( + local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); + if (sdata) { + ieee80211_vif_release_channel(sdata); + ret = ieee80211_vif_use_channel( + sdata, chan, channel_type, + IEEE80211_CHANCTX_EXCLUSIVE); + } + } else if (local->open_count == local->monitors) { + local->_oper_channel = chan; + local->_oper_channel_type = channel_type; + ieee80211_hw_config(local, 0); + } - return 0; -} + if (ret == 0) { + local->monitor_channel = chan; + local->monitor_channel_type = channel_type; + } + mutex_unlock(&local->iflist_mtx); -static int ieee80211_set_monitor_channel(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - return ieee80211_set_channel(wiphy, NULL, chan, channel_type); + return ret; } static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, @@ -879,8 +884,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (old) return -EALREADY; - err = ieee80211_set_channel(wiphy, dev, params->channel, - params->channel_type); + err = ieee80211_vif_use_channel(sdata, params->channel, + params->channel_type, + IEEE80211_CHANCTX_SHARED); if (err) return err; @@ -963,6 +969,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) sta_info_flush(sdata->local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_vif_release_channel(sdata); + return 0; } @@ -1019,9 +1027,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, int i, j; struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); u32 mask, set; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + sband = local->hw.wiphy->bands[band]; mask = params->sta_flags_mask; set = params->sta_flags_set; @@ -1136,7 +1145,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, rates |= BIT(j); } } - sta->sta.supp_rates[local->oper_channel->band] = rates; + sta->sta.supp_rates[band] = rates; } if (params->ht_capa) @@ -1664,8 +1673,9 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, if (err) return err; - err = ieee80211_set_channel(wiphy, dev, setup->channel, - setup->channel_type); + err = ieee80211_vif_use_channel(sdata, setup->channel, + setup->channel_type, + IEEE80211_CHANCTX_SHARED); if (err) return err; @@ -1679,6 +1689,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ieee80211_stop_mesh(sdata); + ieee80211_vif_release_channel(sdata); return 0; } @@ -1688,10 +1699,14 @@ static int ieee80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + enum ieee80211_band band; u32 changed = 0; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (!rtnl_dereference(sdata->u.ap.beacon)) + return -ENOENT; + + band = ieee80211_get_sdata_band(sdata); if (params->use_cts_prot >= 0) { sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; @@ -1704,7 +1719,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, } if (!sdata->vif.bss_conf.use_short_slot && - sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) { + band == IEEE80211_BAND_5GHZ) { sdata->vif.bss_conf.use_short_slot = true; changed |= BSS_CHANGED_ERP_SLOT; } @@ -1718,9 +1733,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, if (params->basic_rates) { int i, j; u32 rates = 0; - struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_supported_band *sband = - wiphy->bands[local->oper_channel->band]; + struct ieee80211_supported_band *sband = wiphy->bands[band]; for (i = 0; i < params->basic_rates_len; i++) { int rate = (params->basic_rates[i] & 0x7f) * 5; @@ -1872,20 +1885,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { - struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (ieee80211_get_channel_mode(local, sdata)) { - case CHAN_MODE_HOPPING: - return -EBUSY; - case CHAN_MODE_FIXED: - if (local->oper_channel == req->bss->channel) - break; - return -EBUSY; - case CHAN_MODE_UNDEFINED: - break; - } - return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } @@ -1904,30 +1903,12 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) { - struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (ieee80211_get_channel_mode(local, sdata)) { - case CHAN_MODE_HOPPING: - return -EBUSY; - case CHAN_MODE_FIXED: - if (!params->channel_fixed) - return -EBUSY; - if (local->oper_channel == params->channel) - break; - return -EBUSY; - case CHAN_MODE_UNDEFINED: - break; - } - - return ieee80211_ibss_join(sdata, params); + return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params); } static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - return ieee80211_ibss_leave(sdata); + return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); } static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) @@ -1971,9 +1952,13 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_channel *chan = local->oper_channel; + struct ieee80211_channel *chan = local->_oper_channel; u32 changes = 0; + /* FIXME */ + if (local->use_chanctx) + return -EOPNOTSUPP; + switch (type) { case NL80211_TX_POWER_AUTOMATIC: local->user_power_level = -1; @@ -2518,10 +2503,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, /* Check if the operating channel is the requested channel */ if (!need_offchan) { - need_offchan = chan != local->oper_channel; - if (channel_type_valid && - channel_type != local->_oper_channel_type) + struct ieee80211_chanctx_conf *chanctx_conf; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + + if (chanctx_conf) { + need_offchan = chan != chanctx_conf->channel; + if (channel_type_valid && + channel_type != chanctx_conf->channel_type) + need_offchan = true; + } else { need_offchan = true; + } + rcu_read_unlock(); } if (need_offchan && !offchan) { @@ -2670,7 +2665,7 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) u16 capab; capab = 0; - if (local->oper_channel->band != IEEE80211_BAND_2GHZ) + if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) return capab; if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) @@ -2702,7 +2697,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_tdls_data *tf; tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); @@ -2722,10 +2717,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_req.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false, - local->oper_channel->band); - ieee80211_add_ext_srates_ie(sdata, skb, false, - local->oper_channel->band); + ieee80211_add_srates_ie(sdata, skb, false, band); + ieee80211_add_ext_srates_ie(sdata, skb, false, band); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_RESPONSE: @@ -2738,10 +2731,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false, - local->oper_channel->band); - ieee80211_add_ext_srates_ie(sdata, skb, false, - local->oper_channel->band); + ieee80211_add_srates_ie(sdata, skb, false, band); + ieee80211_add_ext_srates_ie(sdata, skb, false, band); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_CONFIRM: @@ -2779,7 +2770,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_mgmt *mgmt; mgmt = (void *)skb_put(skb, 24); @@ -2802,10 +2793,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false, - local->oper_channel->band); - ieee80211_add_ext_srates_ie(sdata, skb, false, - local->oper_channel->band); + ieee80211_add_srates_ie(sdata, skb, false, band); + ieee80211_add_ext_srates_ie(sdata, skb, false, band); ieee80211_tdls_add_ext_capab(skb); break; default: @@ -2985,12 +2974,19 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, bool qos; struct ieee80211_tx_info *info; struct sta_info *sta; + struct ieee80211_chanctx_conf *chanctx_conf; + enum ieee80211_band band; rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return -EINVAL; + } + band = chanctx_conf->channel->band; sta = sta_info_get(sdata, peer); if (sta) { qos = test_sta_flag(sta, WLAN_STA_WME); - rcu_read_unlock(); } else { rcu_read_unlock(); return -ENOLINK; @@ -3008,8 +3004,10 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, } skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); - if (!skb) + if (!skb) { + rcu_read_unlock(); return -ENOMEM; + } skb->dev = dev; @@ -3034,8 +3032,9 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, nullfunc->qos_ctrl = cpu_to_le16(7); local_bh_disable(); - ieee80211_xmit(sdata, skb); + ieee80211_xmit(sdata, skb, band); local_bh_enable(); + rcu_read_unlock(); *cookie = (unsigned long) skb; return 0; @@ -3045,10 +3044,19 @@ static struct ieee80211_channel * ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_channel_type *type) { - struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan = NULL; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (chanctx_conf) { + *type = chanctx_conf->channel_type; + chan = chanctx_conf->channel; + } + rcu_read_unlock(); - *type = local->_oper_channel_type; - return local->oper_channel; + return chan; } #ifdef CONFIG_PM diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 1a8dee42e546..41e1aa69f7aa 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -7,106 +7,6 @@ #include "ieee80211_i.h" #include "driver-ops.h" -static enum ieee80211_chan_mode -__ieee80211_get_channel_mode(struct ieee80211_local *local, - struct ieee80211_sub_if_data *ignore) -{ - struct ieee80211_sub_if_data *sdata; - - lockdep_assert_held(&local->iflist_mtx); - - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata == ignore) - continue; - - if (!ieee80211_sdata_running(sdata)) - continue; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_MONITOR: - continue; - case NL80211_IFTYPE_STATION: - if (!sdata->u.mgd.associated) - continue; - break; - case NL80211_IFTYPE_ADHOC: - if (!sdata->u.ibss.ssid_len) - continue; - if (!sdata->u.ibss.fixed_channel) - return CHAN_MODE_HOPPING; - break; - case NL80211_IFTYPE_AP_VLAN: - /* will also have _AP interface */ - continue; - case NL80211_IFTYPE_AP: - if (!sdata->u.ap.beacon) - continue; - break; - case NL80211_IFTYPE_MESH_POINT: - if (!sdata->wdev.mesh_id_len) - continue; - break; - default: - break; - } - - return CHAN_MODE_FIXED; - } - - return CHAN_MODE_UNDEFINED; -} - -enum ieee80211_chan_mode -ieee80211_get_channel_mode(struct ieee80211_local *local, - struct ieee80211_sub_if_data *ignore) -{ - enum ieee80211_chan_mode mode; - - mutex_lock(&local->iflist_mtx); - mode = __ieee80211_get_channel_mode(local, ignore); - mutex_unlock(&local->iflist_mtx); - - return mode; -} - -static enum nl80211_channel_type -ieee80211_get_superchan(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) -{ - enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; - struct ieee80211_sub_if_data *tmp; - - mutex_lock(&local->iflist_mtx); - list_for_each_entry(tmp, &local->interfaces, list) { - if (tmp == sdata) - continue; - - if (!ieee80211_sdata_running(tmp)) - continue; - - switch (tmp->vif.bss_conf.channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - if (superchan > tmp->vif.bss_conf.channel_type) - break; - - superchan = tmp->vif.bss_conf.channel_type; - break; - case NL80211_CHAN_HT40PLUS: - WARN_ON(superchan == NL80211_CHAN_HT40MINUS); - superchan = NL80211_CHAN_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - WARN_ON(superchan == NL80211_CHAN_HT40PLUS); - superchan = NL80211_CHAN_HT40MINUS; - break; - } - } - mutex_unlock(&local->iflist_mtx); - - return superchan; -} - static bool ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, enum nl80211_channel_type chantype2, @@ -149,26 +49,6 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, return true; } -bool ieee80211_set_channel_type(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - enum nl80211_channel_type chantype) -{ - enum nl80211_channel_type superchan; - enum nl80211_channel_type compatchan; - - superchan = ieee80211_get_superchan(local, sdata); - if (!ieee80211_channel_types_are_compatible(superchan, chantype, - &compatchan)) - return false; - - local->_oper_channel_type = compatchan; - - if (sdata) - sdata->vif.bss_conf.channel_type = chantype; - - return true; -} - static void ieee80211_change_chantype(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, enum nl80211_channel_type chantype) @@ -178,6 +58,11 @@ static void ieee80211_change_chantype(struct ieee80211_local *local, ctx->conf.channel_type = chantype; drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); + + if (!local->use_chanctx) { + local->_oper_channel_type = chantype; + ieee80211_hw_config(local, 0); + } } static struct ieee80211_chanctx * @@ -235,10 +120,16 @@ ieee80211_new_chanctx(struct ieee80211_local *local, ctx->conf.channel_type = channel_type; ctx->mode = mode; - err = drv_add_chanctx(local, ctx); - if (err) { - kfree(ctx); - return ERR_PTR(err); + if (!local->use_chanctx) { + local->_oper_channel_type = channel_type; + local->_oper_channel = channel; + ieee80211_hw_config(local, 0); + } else { + err = drv_add_chanctx(local, ctx); + if (err) { + kfree(ctx); + return ERR_PTR(err); + } } list_add(&ctx->list, &local->chanctx_list); @@ -253,7 +144,12 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, WARN_ON_ONCE(ctx->refcount != 0); - drv_remove_chanctx(local, ctx); + if (!local->use_chanctx) { + local->_oper_channel_type = NL80211_CHAN_NO_HT; + ieee80211_hw_config(local, 0); + } else { + drv_remove_chanctx(local, ctx); + } list_del(&ctx->list); kfree_rcu(ctx, rcu_head); @@ -359,6 +255,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx *ctx; int ret; + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); + mutex_lock(&local->chanctx_mtx); __ieee80211_vif_release_channel(sdata); @@ -370,6 +268,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, goto out; } + sdata->vif.bss_conf.channel_type = channel_type; + ret = ieee80211_assign_vif_chanctx(sdata, ctx); if (ret) { /* if assign fails refcount stays the same */ @@ -385,6 +285,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) { + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); + mutex_lock(&sdata->local->chanctx_mtx); __ieee80211_vif_release_channel(sdata); mutex_unlock(&sdata->local->chanctx_mtx); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5f3620f0bc0a..34d9235117d9 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -26,7 +26,6 @@ #include "rate.h" #define IEEE80211_SCAN_INTERVAL (2 * HZ) -#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) @@ -76,21 +75,22 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS); } - memcpy(ifibss->bssid, bssid, ETH_ALEN); - sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - local->oper_channel = chan; channel_type = ifibss->channel_type; if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) channel_type = NL80211_CHAN_HT20; - if (!ieee80211_set_channel_type(local, sdata, channel_type)) { - /* can only fail due to HT40+/- mismatch */ - channel_type = NL80211_CHAN_HT20; - WARN_ON(!ieee80211_set_channel_type(local, sdata, - NL80211_CHAN_HT20)); + + ieee80211_vif_release_channel(sdata); + if (ieee80211_vif_use_channel(sdata, chan, channel_type, + ifibss->fixed_channel ? + IEEE80211_CHANCTX_SHARED : + IEEE80211_CHANCTX_EXCLUSIVE)) { + sdata_info(sdata, "Failed to join IBSS, no channel context\n"); + return; } - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + memcpy(ifibss->bssid, bssid, ETH_ALEN); sband = local->hw.wiphy->bands[chan->band]; @@ -294,7 +294,8 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - int band = local->oper_channel->band; + struct ieee80211_chanctx_conf *chanctx_conf; + int band; /* * XXX: Consider removing the least recently used entry and @@ -317,6 +318,13 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, return NULL; } + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON_ONCE(!chanctx_conf)) + return NULL; + band = chanctx_conf->channel->band; + rcu_read_unlock(); + sta = sta_info_alloc(sdata, addr, GFP_KERNEL); if (!sta) { rcu_read_lock(); @@ -517,7 +525,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* different channel */ - if (cbss->channel != local->oper_channel) + if (sdata->u.ibss.fixed_channel && + sdata->u.ibss.channel != cbss->channel) goto put_bss; /* different SSID */ @@ -592,7 +601,8 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - int band = local->oper_channel->band; + struct ieee80211_chanctx_conf *chanctx_conf; + int band; /* * XXX: Consider removing the least recently used entry and @@ -610,6 +620,15 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) return; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON_ONCE(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + band = chanctx_conf->channel->band; + rcu_read_unlock(); + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return; @@ -784,18 +803,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) int interval = IEEE80211_SCAN_INTERVAL; if (time_after(jiffies, ifibss->ibss_join_req + - IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { - ieee80211_sta_create_ibss(sdata); - return; - } - sdata_info(sdata, "IBSS not allowed on %d MHz\n", - local->oper_channel->center_freq); - - /* No IBSS found - decrease scan interval and continue - * scanning. */ - interval = IEEE80211_SCAN_INTERVAL_SLOW; - } + IEEE80211_IBSS_JOIN_TIMEOUT)) + ieee80211_sta_create_ibss(sdata); mod_timer(&ifibss->timer, round_jiffies(jiffies + interval)); @@ -1086,17 +1095,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.channel_type = params->channel_type; sdata->u.ibss.fixed_channel = params->channel_fixed; - /* fix ourselves to that channel now already */ - if (params->channel_fixed) { - sdata->local->oper_channel = params->channel; - if (!ieee80211_set_channel_type(sdata->local, sdata, - params->channel_type)) { - mutex_unlock(&sdata->u.ibss.mtx); - kfree_skb(skb); - return -EINVAL; - } - } - if (params->ie) { sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, GFP_KERNEL); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8fa00adcb8c0..6660118b46b3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -773,6 +773,21 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) return container_of(p, struct ieee80211_sub_if_data, vif); } +static inline enum ieee80211_band +ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) +{ + enum ieee80211_band band = IEEE80211_BAND_2GHZ; + struct ieee80211_chanctx_conf *chanctx_conf; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!WARN_ON(!chanctx_conf)) + band = chanctx_conf->channel->band; + rcu_read_unlock(); + + return band; +} + enum sdata_queue_type { IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, IEEE80211_SDATA_QUEUE_AGG_START = 1, @@ -1006,8 +1021,10 @@ struct ieee80211_local { enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data __rcu *scan_sdata; + struct ieee80211_channel *csa_channel; + /* For backward compatibility only -- do not use */ + struct ieee80211_channel *_oper_channel; enum nl80211_channel_type _oper_channel_type; - struct ieee80211_channel *oper_channel, *csa_channel; /* Temporary remain-on-channel for off-channel operations */ struct ieee80211_channel *tmp_channel; @@ -1121,6 +1138,8 @@ struct ieee80211_local { /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; + struct ieee80211_channel *monitor_channel; + enum nl80211_channel_type monitor_channel_type; }; static inline struct ieee80211_sub_if_data * @@ -1423,11 +1442,42 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke gfp_t gfp); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, bool bss_notify); -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, + enum ieee80211_band band); + +void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid, + enum ieee80211_band band); + +static inline void +ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid, + enum ieee80211_band band) +{ + rcu_read_lock(); + __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + rcu_read_unlock(); +} -void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid); -static void inline ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, +static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + kfree_skb(skb); + return; + } + + __ieee80211_tx_skb_tid_band(sdata, skb, tid, + chanctx_conf->channel->band); + rcu_read_unlock(); +} + +static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ @@ -1494,7 +1544,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u32 ratemask, bool directed, bool no_cck, - struct ieee80211_channel *channel); + struct ieee80211_channel *channel, bool scan); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, @@ -1525,18 +1575,6 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, enum ieee80211_band band); /* channel management */ -enum ieee80211_chan_mode { - CHAN_MODE_UNDEFINED, - CHAN_MODE_HOPPING, - CHAN_MODE_FIXED, -}; - -enum ieee80211_chan_mode -ieee80211_get_channel_mode(struct ieee80211_local *local, - struct ieee80211_sub_if_data *ignore); -bool ieee80211_set_channel_type(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - enum nl80211_channel_type chantype); enum nl80211_channel_type ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6f8a73c64fb3..7cb8382b19e5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -380,6 +380,15 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) goto out_unlock; } + ret = ieee80211_vif_use_channel(sdata, local->monitor_channel, + local->monitor_channel_type, + IEEE80211_CHANCTX_EXCLUSIVE); + if (ret) { + drv_remove_interface(local, sdata); + kfree(sdata); + goto out_unlock; + } + rcu_assign_pointer(local->monitor_sdata, sdata); out_unlock: mutex_unlock(&local->iflist_mtx); @@ -403,6 +412,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) rcu_assign_pointer(local->monitor_sdata, NULL); synchronize_net(); + ieee80211_vif_release_channel(sdata); + drv_remove_interface(local, sdata); kfree(sdata); @@ -665,7 +676,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, *tmp; u32 hw_reconf_flags = 0; int i; - enum nl80211_channel_type orig_ct; clear_bit(SDATA_STATE_RUNNING, &sdata->state); @@ -837,14 +847,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, hw_reconf_flags = 0; } - /* Re-calculate channel-type, in case there are multiple vifs - * on different channel types. - */ - orig_ct = local->_oper_channel_type; - ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT); - /* do after stop to avoid reconfiguring when we stop anyway */ - if (hw_reconf_flags || (orig_ct != local->_oper_channel_type)) + if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); spin_lock_irqsave(&local->queue_stop_reason_lock, flags); @@ -1282,11 +1286,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, if (type == ieee80211_vif_type_p2p(&sdata->vif)) return 0; - /* Setting ad-hoc mode on non-IBSS channel is not supported. */ - if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS && - type == NL80211_IFTYPE_ADHOC) - return -EOPNOTSUPP; - if (ieee80211_sdata_running(sdata)) { ret = ieee80211_runtime_change_iftype(sdata, type); if (ret) @@ -1298,9 +1297,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, } /* reset some values that shouldn't be kept across type changes */ - sdata->vif.bss_conf.basic_rates = - ieee80211_mandatory_rates(sdata->local, - sdata->local->oper_channel->band); sdata->drop_unencrypted = 0; if (type == NL80211_IFTYPE_STATION) sdata->u.mgd.use_4addr = false; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0dd1ea241c54..9cb6280aa2f2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -93,23 +93,21 @@ static void ieee80211_reconfig_filter(struct work_struct *work) ieee80211_configure_filter(local); } -int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) +static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) { struct ieee80211_channel *chan; - int ret = 0; + u32 changed = 0; int power; enum nl80211_channel_type channel_type; u32 offchannel_flag; - might_sleep(); - offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; if (local->scan_channel) { chan = local->scan_channel; /* If scanning on oper channel, use whatever channel-type * is currently in use. */ - if (chan == local->oper_channel) + if (chan == local->_oper_channel) channel_type = local->_oper_channel_type; else channel_type = NL80211_CHAN_NO_HT; @@ -117,11 +115,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) chan = local->tmp_channel; channel_type = local->tmp_channel_type; } else { - chan = local->oper_channel; + chan = local->_oper_channel; channel_type = local->_oper_channel_type; } - if (chan != local->oper_channel || + if (chan != local->_oper_channel || channel_type != local->_oper_channel_type) local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; else @@ -164,6 +162,21 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) local->hw.conf.power_level = power; } + return changed; +} + +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) +{ + int ret = 0; + + might_sleep(); + + if (!local->use_chanctx) + changed |= ieee80211_hw_conf_chan(local); + else + changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_POWER); + if (changed && local->open_count) { ret = drv_config(local, changed); /* @@ -775,12 +788,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) sband = local->hw.wiphy->bands[band]; if (!sband) continue; - if (!local->oper_channel) { + if (!local->use_chanctx && !local->_oper_channel) { /* init channel we're on */ local->hw.conf.channel = - local->oper_channel = &sband->channels[0]; + local->_oper_channel = &sband->channels[0]; local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } + if (!local->monitor_channel) { + local->monitor_channel = &sband->channels[0]; + local->monitor_channel_type = NL80211_CHAN_NO_HT; + } channels += sband->n_channels; if (max_bitrates < sband->n_bitrates) @@ -810,19 +827,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); - /* - * mac80211 doesn't support more than 1 channel, and also not more - * than one IBSS interface - */ + /* mac80211 doesn't support more than one IBSS interface right now */ for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; int j; c = &hw->wiphy->iface_combinations[i]; - if (c->num_different_channels > 1) - return -EINVAL; - for (j = 0; j < c->n_limits; j++) if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && c->limits[j].max > 1) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ff0296c7bab8..19725e0a051a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -97,7 +97,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) goto mismatch; - ieee80211_sta_get_rates(local, ie, local->oper_channel->band, + ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata), &basic_rates); if (sdata->vif.bss_conf.basic_rates != basic_rates) @@ -355,12 +355,22 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - struct ieee80211_channel *chan = local->oper_channel; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; u8 *pos; if (skb_tailroom(skb) < 3) return -ENOMEM; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return -EINVAL; + } + chan = chanctx_conf->channel; + rcu_read_unlock(); + sband = local->hw.wiphy->bands[chan->band]; if (sband->band == IEEE80211_BAND_2GHZ) { pos = skb_put(skb, 2 + 1); @@ -376,10 +386,11 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_supported_band *sband; u8 *pos; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + sband = local->hw.wiphy->bands[band]; if (!sband->ht_cap.ht_supported || sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) return 0; @@ -397,14 +408,26 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - struct ieee80211_channel *channel = local->oper_channel; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *channel; enum nl80211_channel_type channel_type = - sdata->vif.bss_conf.channel_type; - struct ieee80211_supported_band *sband = - local->hw.wiphy->bands[channel->band]; - struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; + sdata->vif.bss_conf.channel_type; + struct ieee80211_supported_band *sband; + struct ieee80211_sta_ht_cap *ht_cap; u8 *pos; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return -EINVAL; + } + channel = chanctx_conf->channel; + rcu_read_unlock(); + + sband = local->hw.wiphy->bands[channel->band]; + ht_cap = &sband->ht_cap; + if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) return 0; @@ -610,7 +633,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sdata->local, - sdata->local->oper_channel->band); + ieee80211_get_sdata_band(sdata)); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_HT | diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3ab34d816897..8a8b459610b6 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -252,6 +252,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.self_prot.action_code = action; if (action != WLAN_SP_MESH_PEERING_CLOSE) { + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + /* capability info */ pos = skb_put(skb, 2); memset(pos, 0, 2); @@ -260,10 +262,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2); memcpy(pos + 2, &plid, 2); } - if (ieee80211_add_srates_ie(sdata, skb, true, - local->oper_channel->band) || - ieee80211_add_ext_srates_ie(sdata, skb, true, - local->oper_channel->band) || + if (ieee80211_add_srates_ie(sdata, skb, true, band) || + ieee80211_add_ext_srates_ie(sdata, skb, true, band) || mesh_add_rsn_ie(skb, sdata) || mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) @@ -343,7 +343,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems) { struct ieee80211_local *local = sdata->local; - enum ieee80211_band band = local->oper_channel->band; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_supported_band *sband; u32 rates, basic_rates = 0; struct sta_info *sta; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e714ed8bb198..4add50063161 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -178,20 +178,30 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; struct sta_info *sta; u32 changed = 0; u16 ht_opmode; bool disable_40 = false; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return 0; + } + chan = chanctx_conf->channel; + rcu_read_unlock(); + sband = local->hw.wiphy->bands[chan->band]; switch (sdata->vif.bss_conf.channel_type) { case NL80211_CHAN_HT40PLUS: - if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) + if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) disable_40 = true; break; case NL80211_CHAN_HT40MINUS: - if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) + if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) disable_40 = true; break; default: @@ -359,11 +369,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) int i, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; u32 rates = 0; lockdep_assert_held(&ifmgd->mtx); - sband = local->hw.wiphy->bands[local->oper_channel->band]; + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + chan = chanctx_conf->channel; + rcu_read_unlock(); + sband = local->hw.wiphy->bands[chan->band]; if (assoc_data->supp_rates_len) { /* @@ -485,7 +505,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) *pos++ = WLAN_EID_PWR_CAPABILITY; *pos++ = 2; *pos++ = 0; /* min tx power */ - *pos++ = local->oper_channel->max_power; /* max tx power */ + *pos++ = chan->max_power; /* max tx power */ /* 2. supported channels */ /* TODO: get this in reg domain format */ @@ -523,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, - sband, local->oper_channel, ifmgd->ap_smps); + sband, chan, ifmgd->ap_smps); if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_add_vht_ie(sdata, skb, sband); @@ -657,18 +677,18 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ifmgd->associated) goto out; - sdata->local->oper_channel = sdata->local->csa_channel; + sdata->local->_oper_channel = sdata->local->csa_channel; if (!sdata->local->ops->channel_switch) { /* call "hw_config" only if doing sw channel switch */ ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); } else { /* update the device channel directly */ - sdata->local->hw.conf.channel = sdata->local->oper_channel; + sdata->local->hw.conf.channel = sdata->local->_oper_channel; } /* XXX: shouldn't really modify cfg80211-owned data! */ - ifmgd->associated->channel = sdata->local->oper_channel; + ifmgd->associated->channel = sdata->local->_oper_channel; /* XXX: wait for a beacon first? */ ieee80211_wake_queues_by_reason(&sdata->local->hw, @@ -680,11 +700,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) { - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_managed *ifmgd; - - sdata = vif_to_sdata(vif); - ifmgd = &sdata->u.mgd; + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; trace_api_chswitch_done(sdata, success); if (!success) { @@ -723,6 +740,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, cbss->channel->band); + struct ieee80211_chanctx *chanctx; ASSERT_MGD_MTX(ifmgd); @@ -748,10 +766,34 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; } - sdata->local->csa_channel = new_ch; - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + if (sdata->local->use_chanctx) { + sdata_info(sdata, + "not handling channel switch with channel contexts\n"); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + } + + mutex_lock(&sdata->local->chanctx_mtx); + if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { + mutex_unlock(&sdata->local->chanctx_mtx); + return; + } + chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), + struct ieee80211_chanctx, conf); + if (chanctx->refcount > 1) { + sdata_info(sdata, + "channel switch with multiple interfaces on the same channel, disconnecting\n"); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + mutex_unlock(&sdata->local->chanctx_mtx); + return; + } + mutex_unlock(&sdata->local->chanctx_mtx); + + sdata->local->csa_channel = new_ch; + if (sw_elem->mode) ieee80211_stop_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -1280,7 +1322,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); - if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) + if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_5GHZ) use_short_slot = true; if (use_protection != bss_conf->use_cts_prot) { @@ -1465,9 +1507,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); - /* channel(_type) changes are handled by ieee80211_hw_config */ - WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); - ieee80211_hw_config(local, 0); + ieee80211_vif_release_channel(sdata); /* disassociated - set to defaults now */ ieee80211_set_wmm_default(sdata, false); @@ -1589,7 +1629,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, 0, (u32) -1, true, false, - ifmgd->associated->channel); + ifmgd->associated->channel, false); } ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); @@ -1692,8 +1732,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ssid_len = ssid[1]; skb = ieee80211_build_probe_req(sdata, cbss->bssid, - (u32) -1, - sdata->local->oper_channel, + (u32) -1, cbss->channel, ssid + 2, ssid_len, NULL, 0, true); @@ -1804,6 +1843,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, memset(sdata->u.mgd.bssid, 0, ETH_ALEN); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_vif_release_channel(sdata); } cfg80211_put_bss(auth_data->bss); @@ -2030,6 +2070,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, memset(sdata->u.mgd.bssid, 0, ETH_ALEN); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_vif_release_channel(sdata); } kfree(assoc_data); @@ -2091,7 +2132,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, return false; } - sband = local->hw.wiphy->bands[local->oper_channel->band]; + sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, @@ -2369,6 +2410,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, size_t baselen; struct ieee802_11_elems elems; struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; u32 changed = 0; bool erp_valid, directed_tim = false; u8 erp_value = 0; @@ -2382,8 +2425,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (baselen > len) return; - if (rx_status->freq != local->oper_channel->center_freq) + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); return; + } + + if (rx_status->freq != chanctx_conf->channel->center_freq) { + rcu_read_unlock(); + return; + } + chan = chanctx_conf->channel; + rcu_read_unlock(); if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { @@ -2546,7 +2600,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + sband = local->hw.wiphy->bands[chan->band]; changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, bssid, true); @@ -2555,7 +2609,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.country_elem && elems.pwr_constr_elem && mgmt->u.probe_resp.capab_info & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) - ieee80211_handle_pwr_constr(sdata, local->oper_channel, + ieee80211_handle_pwr_constr(sdata, chan, elems.country_elem, elems.country_elem_len, elems.pwr_constr_elem); @@ -2728,7 +2782,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) */ ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], NULL, 0, (u32) -1, true, false, - auth_data->bss->channel); + auth_data->bss->channel, false); } auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; @@ -3118,20 +3172,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } } - if (!ieee80211_set_channel_type(local, sdata, channel_type)) { - /* can only fail due to HT40+/- mismatch */ - channel_type = NL80211_CHAN_HT20; - sdata_info(sdata, - "disabling 40 MHz due to multi-vif mismatch\n"); - ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; - WARN_ON(!ieee80211_set_channel_type(local, sdata, - channel_type)); - } - - local->oper_channel = cbss->channel; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - - return 0; + ieee80211_vif_release_channel(sdata); + return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type, + IEEE80211_CHANCTX_SHARED); } static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, @@ -3201,7 +3244,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ - if (local->oper_channel->band == IEEE80211_BAND_2GHZ && + if (cbss->channel->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 9c52fc4a045e..c349f3aaf59e 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -199,7 +199,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) if (roc->mgmt_tx_cookie) { if (!WARN_ON(!roc->frame)) { - ieee80211_tx_skb(roc->sdata, roc->frame); + ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7, + roc->chan->band); roc->frame = NULL; } } else { diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5c572e7a1a71..9f404ac901ab 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -135,6 +135,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + /* the interface is leaving the channel and is removed */ + ieee80211_vif_release_channel(sdata); drv_remove_interface(local, sdata); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 10de668eb9f6..ec198ef6aa8a 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -52,11 +52,21 @@ static inline void rate_control_rate_init(struct sta_info *sta) struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; struct ieee80211_supported_band *sband; + struct ieee80211_chanctx_conf *chanctx_conf; if (!ref) return; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + rcu_read_lock(); + + chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + + sband = local->hw.wiphy->bands[chanctx_conf->channel->band]; + rcu_read_unlock(); ref->ops->rate_init(ref->priv, sband, ista, priv_sta); set_sta_flag(sta, WLAN_STA_RATE_CONTROL); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index fdaa505dab45..987c75d46bc0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -421,7 +421,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, local->scan_req->ie, local->scan_req->ie_len, local->scan_req->rates[band], false, local->scan_req->no_cck, - local->hw.conf.channel); + local->hw.conf.channel, true); /* * After sending probe requests, wait for probe responses @@ -484,7 +484,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); } else if ((req->n_channels == 1) && - (req->channels[0] == local->oper_channel)) { + (req->channels[0] == local->_oper_channel)) { /* * If we are scanning only on the operating channel * then we do not need to stop normal activities diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 797dd36a220d..fa639f41aa5b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1008,6 +1008,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, __le16 fc; bool qos = test_sta_flag(sta, WLAN_STA_WME); struct ieee80211_tx_info *info; + struct ieee80211_chanctx_conf *chanctx_conf; if (qos) { fc = cpu_to_le16(IEEE80211_FTYPE_DATA | @@ -1057,7 +1058,16 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); - ieee80211_xmit(sdata, skb); + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + kfree_skb(skb); + return; + } + + ieee80211_xmit(sdata, skb, chanctx_conf->channel->band); + rcu_read_unlock(); } static void diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c9bf83f36657..eee448ac71ff 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -324,11 +324,6 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - /* - * virtual interfaces are protected by RCU - */ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { struct ieee80211_if_ap *ap; if (sdata->vif.type != NL80211_IFTYPE_AP) @@ -360,8 +355,6 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } } - rcu_read_unlock(); - local->total_ps_buffered = total; ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged); } @@ -1372,7 +1365,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) * Returns false if the frame couldn't be transmitted but was queued instead. */ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool txpending) + struct sk_buff *skb, bool txpending, + enum ieee80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_data tx; @@ -1386,20 +1380,18 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, return true; } - rcu_read_lock(); - /* initialises tx */ led_len = skb->len; res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); if (unlikely(res_prepare == TX_DROP)) { ieee80211_free_txskb(&local->hw, skb); - goto out; + return true; } else if (unlikely(res_prepare == TX_QUEUED)) { - goto out; + return true; } - info->band = local->hw.conf.channel->band; + info->band = band; /* set up hw_queue value early */ if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || @@ -1410,8 +1402,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, if (!invoke_tx_handlers(&tx)) result = __ieee80211_tx(local, &tx.skbs, led_len, tx.sta, txpending); - out: - rcu_read_unlock(); + return result; } @@ -1446,7 +1437,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, return 0; } -void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) +void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, + enum ieee80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1454,8 +1446,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) int headroom; bool may_encrypt; - rcu_read_lock(); - may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); headroom = local->tx_headroom; @@ -1466,7 +1456,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { ieee80211_free_txskb(&local->hw, skb); - rcu_read_unlock(); return; } @@ -1478,13 +1467,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) !is_multicast_ether_addr(hdr->addr1) && mesh_nexthop_resolve(skb, sdata)) { /* skb queued: don't free */ - rcu_read_unlock(); return; } ieee80211_set_qos_hdr(sdata, skb); - ieee80211_tx(sdata, skb, false); - rcu_read_unlock(); + ieee80211_tx(sdata, skb, false, band); } static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) @@ -1574,7 +1561,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_channel *chan = local->hw.conf.channel; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1583,26 +1571,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, u16 len_rthdr; int hdrlen; - /* - * Frame injection is not allowed if beaconing is not allowed - * or if we need radar detection. Beaconing is usually not allowed when - * the mode or operation (Adhoc, AP, Mesh) does not support DFS. - * Passive scan is also used in world regulatory domains where - * your country is not known and as such it should be treated as - * NO TX unless the channel is explicitly allowed in which case - * your current regulatory domain would not have the passive scan - * flag. - * - * Since AP mode uses monitor interfaces to inject/TX management - * frames we can make AP mode the exception to this rule once it - * supports radar detection as its implementation can deal with - * radar detection by itself. We can do that later by adding a - * monitor flag interfaces used for AP support. - */ - if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN))) - goto fail; - /* check for not even having the fixed radiotap header part */ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) goto fail; /* too short to be possibly valid */ @@ -1688,11 +1656,45 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, } } - ieee80211_xmit(sdata, skb); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) { + tmp_sdata = rcu_dereference(local->monitor_sdata); + if (tmp_sdata) + chanctx_conf = + rcu_dereference(tmp_sdata->vif.chanctx_conf); + } + if (!chanctx_conf) + goto fail_rcu; + + chan = chanctx_conf->channel; + + /* + * Frame injection is not allowed if beaconing is not allowed + * or if we need radar detection. Beaconing is usually not allowed when + * the mode or operation (Adhoc, AP, Mesh) does not support DFS. + * Passive scan is also used in world regulatory domains where + * your country is not known and as such it should be treated as + * NO TX unless the channel is explicitly allowed in which case + * your current regulatory domain would not have the passive scan + * flag. + * + * Since AP mode uses monitor interfaces to inject/TX management + * frames we can make AP mode the exception to this rule once it + * supports radar detection as its implementation can deal with + * radar detection by itself. We can do that later by adding a + * monitor flag interfaces used for AP support. + */ + if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_PASSIVE_SCAN))) + goto fail_rcu; + + ieee80211_xmit(sdata, skb, chan->band); rcu_read_unlock(); return NETDEV_TX_OK; +fail_rcu: + rcu_read_unlock(); fail: dev_kfree_skb(skb); return NETDEV_TX_OK; /* meaning, we dealt with the skb */ @@ -1734,6 +1736,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, bool multicast; u32 info_flags = 0; u16 info_id = 0; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_sub_if_data *ap_sdata; + enum ieee80211_band band; if (unlikely(skb->len < ETH_HLEN)) goto fail; @@ -1743,9 +1748,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ethertype = (skb->data[12] << 8) | skb->data[13]; fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); + rcu_read_lock(); + switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: - rcu_read_lock(); sta = rcu_dereference(sdata->u.vlan.sta); if (sta) { fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); @@ -1758,7 +1764,12 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = test_sta_flag(sta, WLAN_STA_WME); } - rcu_read_unlock(); + ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, + u.ap); + chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); + if (!chanctx_conf) + goto fail_rcu; + band = chanctx_conf->channel->band; if (sta) break; /* fall through */ @@ -1769,6 +1780,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; + if (sdata->vif.type == NL80211_IFTYPE_AP) + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) + goto fail_rcu; + band = chanctx_conf->channel->band; break; case NL80211_IFTYPE_WDS: fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); @@ -1778,15 +1794,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; + /* + * This is the exception! WDS style interfaces are prohibited + * when channel contexts are in used so this must be valid + */ + band = local->hw.conf.channel->band; break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; - goto fail; + goto fail_rcu; } - rcu_read_lock(); + if (!is_multicast_ether_addr(skb->data)) { mpath = mesh_path_lookup(skb->data, sdata); if (!mpath) @@ -1803,7 +1824,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) { hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, skb->data, skb->data + ETH_ALEN); - rcu_read_unlock(); meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, NULL, NULL); } else { @@ -1819,7 +1839,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, mesh_da = mppath->mpp; else if (mpath) mesh_da = mpath->dst; - rcu_read_unlock(); hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, mesh_da, sdata->vif.addr); @@ -1839,13 +1858,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, skb->data + ETH_ALEN); } + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) + goto fail_rcu; + band = chanctx_conf->channel->band; break; #endif case NL80211_IFTYPE_STATION: if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { bool tdls_peer = false; - rcu_read_lock(); sta = sta_info_get(sdata, skb->data); if (sta) { authorized = test_sta_flag(sta, @@ -1856,7 +1878,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, tdls_auth = test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); } - rcu_read_unlock(); /* * If the TDLS link is enabled, send everything @@ -1871,7 +1892,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (tdls_direct) { /* link during setup - throw out frames to peer */ if (!tdls_auth) - goto fail; + goto fail_rcu; /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); @@ -1896,6 +1917,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; } + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) + goto fail_rcu; + band = chanctx_conf->channel->band; break; case NL80211_IFTYPE_ADHOC: /* DA SA BSSID */ @@ -1903,9 +1928,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); hdrlen = 24; + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) + goto fail_rcu; + band = chanctx_conf->channel->band; break; default: - goto fail; + goto fail_rcu; } /* @@ -1915,13 +1944,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ multicast = is_multicast_ether_addr(hdr.addr1); if (!multicast) { - rcu_read_lock(); sta = sta_info_get(sdata, hdr.addr1); if (sta) { authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = test_sta_flag(sta, WLAN_STA_WME); } - rcu_read_unlock(); } /* For mesh, the use of the QoS header is mandatory */ @@ -1949,7 +1976,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); - goto fail; + goto fail_rcu; } if (unlikely(!multicast && skb->sk && @@ -2004,7 +2031,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, kfree_skb(tmp_skb); if (!skb) - goto fail; + goto fail_rcu; } hdr.frame_control = fc; @@ -2052,7 +2079,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, true)) { ieee80211_free_txskb(&local->hw, skb); - return NETDEV_TX_OK; + goto fail_rcu; } } @@ -2104,10 +2131,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, info->flags = info_flags; info->ack_frame_id = info_id; - ieee80211_xmit(sdata, skb); + ieee80211_xmit(sdata, skb, band); + rcu_read_unlock(); return NETDEV_TX_OK; + fail_rcu: + rcu_read_unlock(); fail: dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -2139,11 +2169,18 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, struct sta_info *sta; struct ieee80211_hdr *hdr; bool result; + struct ieee80211_chanctx_conf *chanctx_conf; sdata = vif_to_sdata(info->control.vif); if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - result = ieee80211_tx(sdata, skb, true); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (unlikely(!chanctx_conf)) { + dev_kfree_skb(skb); + return true; + } + result = ieee80211_tx(sdata, skb, true, + chanctx_conf->channel->band); } else { struct sk_buff_head skbs; @@ -2285,14 +2322,16 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; struct beacon_data *beacon; - enum ieee80211_band band = local->oper_channel->band; + enum ieee80211_band band; struct ieee80211_tx_rate_control txrc; + struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); sdata = vif_to_sdata(vif); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (!ieee80211_sdata_running(sdata)) + if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; if (tim_offset) @@ -2409,6 +2448,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *pos++ = WLAN_EID_SSID; *pos++ = 0x0; + band = chanctx_conf->channel->band; + if (ieee80211_add_srates_ie(sdata, skb, true, band) || mesh_add_ds_params_ie(skb, sdata) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) || @@ -2426,6 +2467,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, goto out; } + band = chanctx_conf->channel->band; + info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; @@ -2656,14 +2699,17 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_if_ap *bss = NULL; struct beacon_data *beacon; struct ieee80211_tx_info *info; + struct ieee80211_chanctx_conf *chanctx_conf; sdata = vif_to_sdata(vif); bss = &sdata->u.ap; rcu_read_lock(); beacon = rcu_dereference(bss->beacon); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head) + if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head || + !chanctx_conf) goto out; if (bss->dtim_count != 0 || !bss->dtim_bc_mc) @@ -2693,7 +2739,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); tx.flags |= IEEE80211_TX_PS_BUFFERED; - info->band = local->oper_channel->band; + info->band = chanctx_conf->channel->band; if (invoke_tx_handlers(&tx)) skb = NULL; @@ -2704,8 +2750,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_get_buffered_bc); -void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid) +void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid, + enum ieee80211_band band) { int ac = ieee802_1d_to_ac[tid & 7]; @@ -2722,6 +2769,6 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, * requirements are that we do not come into tx with bhs on. */ local_bh_disable(); - ieee80211_xmit(sdata, skb); + ieee80211_xmit(sdata, skb, band); local_bh_enable(); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22ca35054dd0..7d737071dedb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -832,6 +832,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; + struct ieee80211_chanctx_conf *chanctx_conf; int ac; bool use_11b, enable_qos; int aCWmin, aCWmax; @@ -844,8 +845,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, memset(&qparam, 0, sizeof(qparam)); - use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) && + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + use_11b = (chanctx_conf && + chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); + rcu_read_unlock(); /* * By default disable QoS in STA mode for old access points, which do @@ -924,7 +929,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, const u8 *supp_rates) { - struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; int i, have_higher_than_11mbit = 0; /* cf. IEEE 802.11 9.2.12 */ @@ -932,11 +937,16 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, if ((supp_rates[i] & 0x7f) * 5 > 110) have_higher_than_11mbit = 1; - if (local->oper_channel->band == IEEE80211_BAND_2GHZ && + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + + if (chanctx_conf && + chanctx_conf->channel->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + rcu_read_unlock(); ieee80211_set_wmm_default(sdata, true); } @@ -1206,7 +1216,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u32 ratemask, bool directed, bool no_cck, - struct ieee80211_channel *channel) + struct ieee80211_channel *channel, bool scan) { struct sk_buff *skb; @@ -1217,7 +1227,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, if (no_cck) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; - ieee80211_tx_skb(sdata, skb); + if (scan) + ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); + else + ieee80211_tx_skb(sdata, skb); } } @@ -1280,6 +1293,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_sub_if_data *sdata; + struct ieee80211_chanctx *ctx; struct sta_info *sta; int res, i; @@ -1352,6 +1366,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) res = drv_add_interface(local, sdata); } + /* add channel contexts */ + mutex_lock(&local->chanctx_mtx); + list_for_each_entry(ctx, &local->chanctx_list, list) + WARN_ON(drv_add_chanctx(local, ctx)); + mutex_unlock(&local->chanctx_mtx); + /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { @@ -1392,11 +1412,22 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { + struct ieee80211_chanctx_conf *ctx_conf; u32 changed; if (!ieee80211_sdata_running(sdata)) continue; + mutex_lock(&local->chanctx_mtx); + ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (ctx_conf) { + ctx = container_of(ctx_conf, struct ieee80211_chanctx, + conf); + drv_assign_vif_chanctx(local, sdata, ctx); + } + mutex_unlock(&local->chanctx_mtx); + /* common change flags for all interface types */ changed = BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | From 04ecd2578e712c301fa1369d2a8f298a2b4b146a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Sep 2012 14:34:12 +0200 Subject: [PATCH 08/38] mac80211: track needed RX chains for channel contexts On each channel that the device is operating on, it may need to listen using one or more chains depending on the SMPS settings of the interfaces using it. The previous channel context changes completely removed this ability (before, it was available as the SMPS mode). Add per-context tracking of the required static and dynamic RX chains and notify the driver on changes. To achieve this, track the chains and SMPS mode used on each virtual interface and update the channel context whenever this changes. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++- net/mac80211/cfg.c | 15 ++++-- net/mac80211/chan.c | 90 ++++++++++++++++++++++++++++++++++- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ibss.c | 3 ++ net/mac80211/ieee80211_i.h | 20 ++++++-- net/mac80211/iface.c | 10 ++++ net/mac80211/main.c | 18 +++---- net/mac80211/mlme.c | 28 +++++++++-- net/mac80211/status.c | 15 +++--- net/mac80211/trace.h | 13 +++-- net/mac80211/util.c | 82 +++++++++++-------------------- 12 files changed, 219 insertions(+), 92 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d9d2119f0828..3560881d17ee 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -146,9 +146,11 @@ struct ieee80211_low_level_stats { /** * enum ieee80211_chanctx_change - change flag for channel context * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed + * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed */ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE = BIT(0), + IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), }; /** @@ -159,6 +161,11 @@ enum ieee80211_chanctx_change { * * @channel: the channel to tune to * @channel_type: the channel (HT) type + * @rx_chains_static: The number of RX chains that must always be + * active on the channel to receive MIMO transmissions + * @rx_chains_dynamic: The number of RX chains that must be enabled + * after RTS/CTS handshake to receive SMPS MIMO transmissions; + * this will always be >= @rx_chains_always. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. */ @@ -166,6 +173,8 @@ struct ieee80211_chanctx_conf { struct ieee80211_channel *channel; enum nl80211_channel_type channel_type; + u8 rx_chains_static, rx_chains_dynamic; + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; @@ -820,6 +829,8 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed + * Note that this is only valid if channel contexts are not used, + * otherwise each channel context has the number of chains listed. */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_SMPS = BIT(1), @@ -885,7 +896,9 @@ enum ieee80211_smps_mode { * * @smps_mode: spatial multiplexing powersave mode; note that * %IEEE80211_SMPS_STATIC is used when the device is not - * configured for an HT channel + * configured for an HT channel. + * Note that this is only valid if channel contexts are not used, + * otherwise each channel context has the number of chains listed. */ struct ieee80211_conf { u32 flags; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 09c90627fd19..03216b0408c7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -884,6 +884,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (old) return -EALREADY; + /* TODO: make hostapd tell us what it wants */ + sdata->smps_mode = IEEE80211_SMPS_OFF; + sdata->needed_rx_chains = sdata->local->rx_chains; + err = ieee80211_vif_use_channel(sdata, params->channel, params->channel_type, IEEE80211_CHANCTX_SHARED); @@ -1673,6 +1677,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, if (err) return err; + /* can mesh use other SMPS modes? */ + sdata->smps_mode = IEEE80211_SMPS_OFF; + sdata->needed_rx_chains = sdata->local->rx_chains; + err = ieee80211_vif_use_channel(sdata, setup->channel, setup->channel_type, IEEE80211_CHANCTX_SHARED); @@ -2052,13 +2060,12 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, /* * If not associated, or current association is not an HT - * association, there's no need to send an action frame. + * association, there's no need to do anything, just store + * the new value until we associate. */ if (!sdata->u.mgd.associated || - sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { - ieee80211_recalc_smps(sdata->local); + sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) return 0; - } ap = sdata->u.mgd.associated->bssid; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 41e1aa69f7aa..bfaa486d928c 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -118,6 +118,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local, ctx->conf.channel = channel; ctx->conf.channel_type = channel_type; + ctx->conf.rx_chains_static = 1; + ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; if (!local->use_chanctx) { @@ -222,8 +224,10 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, drv_unassign_vif_chanctx(local, sdata, ctx); - if (ctx->refcount > 0) + if (ctx->refcount > 0) { ieee80211_recalc_chanctx_chantype(sdata->local, ctx); + ieee80211_recalc_smps_chanctx(local, ctx); + } } static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) @@ -246,6 +250,89 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) ieee80211_free_chanctx(local, ctx); } +void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *chanctx) +{ + struct ieee80211_sub_if_data *sdata; + u8 rx_chains_static, rx_chains_dynamic; + + lockdep_assert_held(&local->chanctx_mtx); + + rx_chains_static = 1; + rx_chains_dynamic = 1; + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + u8 needed_static, needed_dynamic; + + if (!ieee80211_sdata_running(sdata)) + continue; + + if (rcu_access_pointer(sdata->vif.chanctx_conf) != + &chanctx->conf) + continue; + + switch (sdata->vif.type) { + case NL80211_IFTYPE_P2P_DEVICE: + continue; + case NL80211_IFTYPE_STATION: + if (!sdata->u.mgd.associated) + continue; + break; + case NL80211_IFTYPE_AP_VLAN: + continue; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + break; + default: + WARN_ON_ONCE(1); + } + + switch (sdata->smps_mode) { + default: + WARN_ONCE(1, "Invalid SMPS mode %d\n", + sdata->smps_mode); + /* fall through */ + case IEEE80211_SMPS_OFF: + needed_static = sdata->needed_rx_chains; + needed_dynamic = sdata->needed_rx_chains; + break; + case IEEE80211_SMPS_DYNAMIC: + needed_static = 1; + needed_dynamic = sdata->needed_rx_chains; + break; + case IEEE80211_SMPS_STATIC: + needed_static = 1; + needed_dynamic = 1; + break; + } + + rx_chains_static = max(rx_chains_static, needed_static); + rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + } + rcu_read_unlock(); + + if (!local->use_chanctx) { + if (rx_chains_static > 1) + local->smps_mode = IEEE80211_SMPS_OFF; + else if (rx_chains_dynamic > 1) + local->smps_mode = IEEE80211_SMPS_DYNAMIC; + else + local->smps_mode = IEEE80211_SMPS_STATIC; + ieee80211_hw_config(local, 0); + } + + if (rx_chains_static == chanctx->conf.rx_chains_static && + rx_chains_dynamic == chanctx->conf.rx_chains_dynamic) + return; + + chanctx->conf.rx_chains_static = rx_chains_static; + chanctx->conf.rx_chains_dynamic = rx_chains_dynamic; + drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS); +} + int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, @@ -278,6 +365,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, goto out; } + ieee80211_recalc_smps_chanctx(local, ctx); out: mutex_unlock(&local->chanctx_mtx); return ret; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 6d5aec9418ee..34e173976573 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -217,7 +217,7 @@ static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, return snprintf(buf, buflen, "request: %s\nused: %s\n", smps_modes[sdata->u.mgd.req_smps], - smps_modes[sdata->u.mgd.ap_smps]); + smps_modes[sdata->smps_mode]); } static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 34d9235117d9..291c9e07f1bd 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1132,6 +1132,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); + sdata->smps_mode = IEEE80211_SMPS_OFF; + sdata->needed_rx_chains = sdata->local->rx_chains; + ieee80211_queue_work(&sdata->local->hw, &sdata->work); return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6660118b46b3..132577d22928 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -433,7 +433,6 @@ struct ieee80211_if_managed { bool powersave; /* powersave requested for this iface */ bool broken_ap; /* AP is broken -- turn off powersave */ enum ieee80211_smps_mode req_smps, /* requested smps mode */ - ap_smps, /* smps mode AP thinks we're in */ driver_smps_mode; /* smps mode request */ struct work_struct request_smps_work; @@ -728,11 +727,17 @@ struct ieee80211_sub_if_data { struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; + /* used to reconfigure hardware SM PS */ + struct work_struct recalc_smps; + struct work_struct work; struct sk_buff_head skb_queue; bool arp_filter_state; + u8 needed_rx_chains; + enum ieee80211_smps_mode smps_mode; + /* * AP this belongs to: self in AP mode and * corresponding AP in VLAN mode, NULL for @@ -905,9 +910,6 @@ struct ieee80211_local { /* used for uploading changed mc list */ struct work_struct reconfig_filter; - /* used to reconfigure hardware SM PS */ - struct work_struct recalc_smps; - /* aggregated multicast list */ struct netdev_hw_addr_list mc_list; @@ -944,6 +946,9 @@ struct ieee80211_local { /* wowlan is enabled -- don't reconfig on resume */ bool wowlan; + /* number of RX chains the hardware has */ + u8 rx_chains; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames @@ -1408,6 +1413,8 @@ void ieee80211_ba_session_work(struct work_struct *work); void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); +u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); + /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, @@ -1554,7 +1561,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, enum ieee80211_band band, u32 *basic_rates); int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode smps_mode); -void ieee80211_recalc_smps(struct ieee80211_local *local); +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); size_t ieee80211_ie_split(const u8 *ies, size_t ielen, const u8 *ids, int n_ids, size_t offset); @@ -1585,6 +1592,9 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, enum ieee80211_chanctx_mode mode); void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, + struct ieee80211_chanctx *chanctx); + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7cb8382b19e5..99f2b19c8f0d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -739,6 +739,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); + cancel_work_sync(&sdata->recalc_smps); + /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { struct ieee80211_sub_if_data *vlan, *tmpsdata; @@ -1125,6 +1127,13 @@ static void ieee80211_iface_work(struct work_struct *work) } } +static void ieee80211_recalc_smps_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, recalc_smps); + + ieee80211_recalc_smps(sdata); +} /* * Helper function to initialise an interface to a specific type. @@ -1153,6 +1162,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sdata->skb_queue); INIT_WORK(&sdata->work, ieee80211_iface_work); + INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); switch (type) { case NL80211_IFTYPE_P2P_GO: diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9cb6280aa2f2..2c8969b67851 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -372,14 +372,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_restart_hw); -static void ieee80211_recalc_smps_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, recalc_smps); - - ieee80211_recalc_smps(local); -} - #ifdef CONFIG_INET static int ieee80211_ifa_changed(struct notifier_block *nb, unsigned long data, void *arg) @@ -667,7 +659,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); - INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); local->smps_mode = IEEE80211_SMPS_OFF; INIT_WORK(&local->dynamic_ps_enable_work, @@ -773,6 +764,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; + local->rx_chains = 1; + /* * generic code guarantees at least one band, * set this very early because much code assumes @@ -804,6 +797,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; supp_vht = supp_vht || sband->vht_cap.vht_supported; + + if (sband->ht_cap.ht_supported) + local->rx_chains = + max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), + local->rx_chains); + + /* TODO: consider VHT for RX chains, hopefully it's the same */ } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4add50063161..f3f338541b01 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -543,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, - sband, chan, ifmgd->ap_smps); + sband, chan, sdata->smps_mode); if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_add_vht_ie(sdata, skb, sband); @@ -1392,7 +1392,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local, -1); mutex_unlock(&local->iflist_mtx); - ieee80211_recalc_smps(local); + ieee80211_recalc_smps(sdata); ieee80211_recalc_ps_vif(sdata); netif_tx_start_all_queues(sdata->dev); @@ -3157,6 +3157,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } if (ht_oper) { + const u8 *ht_cap_ie; + const struct ieee80211_ht_cap *ht_cap; + u8 chains = 1; + channel_type = NL80211_CHAN_HT20; if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { @@ -3170,8 +3174,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, break; } } + + ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + cbss->information_elements, + cbss->len_information_elements); + if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { + ht_cap = (void *)(ht_cap_ie + 2); + chains = ieee80211_mcs_to_chains(&ht_cap->mcs); + } + sdata->needed_rx_chains = min(chains, local->rx_chains); + } else { + sdata->needed_rx_chains = 1; } + /* will change later if needed */ + sdata->smps_mode = IEEE80211_SMPS_OFF; + ieee80211_vif_release_channel(sdata); return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type, IEEE80211_CHANCTX_SHARED); @@ -3485,11 +3503,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { if (ifmgd->powersave) - ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; + sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; else - ifmgd->ap_smps = IEEE80211_SMPS_OFF; + sdata->smps_mode = IEEE80211_SMPS_OFF; } else - ifmgd->ap_smps = ifmgd->req_smps; + sdata->smps_mode = ifmgd->req_smps; assoc_data->capability = req->bss->capability; assoc_data->wmm = bss->wmm_used && diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3af0cc4130f1..21fa5c72ea14 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -189,30 +189,31 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) } if (ieee80211_is_action(mgmt->frame_control) && - sdata->vif.type == NL80211_IFTYPE_STATION && mgmt->u.action.category == WLAN_CATEGORY_HT && - mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) { + mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && + sdata->vif.type == NL80211_IFTYPE_STATION && + ieee80211_sdata_running(sdata)) { /* * This update looks racy, but isn't -- if we come * here we've definitely got a station that we're * talking to, and on a managed interface that can * only be the AP. And the only other place updating - * this variable is before we're associated. + * this variable in managed mode is before association. */ switch (mgmt->u.action.u.ht_smps.smps_control) { case WLAN_HT_SMPS_CONTROL_DYNAMIC: - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC; + sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; break; case WLAN_HT_SMPS_CONTROL_STATIC: - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC; + sdata->smps_mode = IEEE80211_SMPS_STATIC; break; case WLAN_HT_SMPS_CONTROL_DISABLED: default: /* shouldn't happen since we don't send that */ - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF; + sdata->smps_mode = IEEE80211_SMPS_OFF; break; } - ieee80211_queue_work(&local->hw, &local->recalc_smps); + ieee80211_queue_work(&local->hw, &sdata->recalc_smps); } } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index a3f5fe2a84a8..629364705f7b 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -29,11 +29,16 @@ #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" #define CHANCTX_ENTRY __field(int, freq) \ - __field(int, chantype) + __field(int, chantype) \ + __field(u8, rx_chains_static) \ + __field(u8, rx_chains_dynamic) #define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \ - __entry->chantype = ctx->conf.channel_type -#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d" -#define CHANCTX_PR_ARG __entry->freq, __entry->chantype + __entry->chantype = ctx->conf.channel_type; \ + __entry->rx_chains_static = ctx->conf.rx_chains_static; \ + __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic +#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d" +#define CHANCTX_PR_ARG __entry->freq, __entry->chantype, \ + __entry->rx_chains_static, __entry->rx_chains_dynamic diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7d737071dedb..b732e219b107 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1618,68 +1618,24 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif) } EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); -static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, - enum ieee80211_smps_mode *smps_mode) +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) { - if (ifmgd->associated) { - *smps_mode = ifmgd->ap_smps; - - if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { - if (ifmgd->powersave) - *smps_mode = IEEE80211_SMPS_DYNAMIC; - else - *smps_mode = IEEE80211_SMPS_OFF; - } - - return 1; - } - - return 0; -} - -void ieee80211_recalc_smps(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; - int count = 0; - - mutex_lock(&local->iflist_mtx); - - /* - * This function could be improved to handle multiple - * interfaces better, but right now it makes any - * non-station interfaces force SM PS to be turned - * off. If there are multiple station interfaces it - * could also use the best possible mode, e.g. if - * one is in static and the other in dynamic then - * dynamic is ok. - */ - - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) - continue; - if (sdata->vif.type != NL80211_IFTYPE_STATION) - goto set; + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_chanctx *chanctx; - count += check_mgd_smps(&sdata->u.mgd, &smps_mode); + mutex_lock(&local->chanctx_mtx); - if (count > 1) { - smps_mode = IEEE80211_SMPS_OFF; - break; - } - } + chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); - if (smps_mode == local->smps_mode) + if (WARN_ON_ONCE(!chanctx_conf)) goto unlock; - set: - local->smps_mode = smps_mode; - /* changed flag is auto-detected for this */ - ieee80211_hw_config(local, 0); + chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); + ieee80211_recalc_smps_chanctx(local, chanctx); unlock: - mutex_unlock(&local->iflist_mtx); + mutex_unlock(&local->chanctx_mtx); } static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) @@ -1978,3 +1934,19 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif) return ifmgd->ave_beacon_signal; } EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); + +u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs) +{ + if (!mcs) + return 1; + + /* TODO: consider rx_highest */ + + if (mcs->rx_mask[3]) + return 4; + if (mcs->rx_mask[2]) + return 3; + if (mcs->rx_mask[1]) + return 2; + return 1; +} From 3448c0058327356049f140116fc6632bbfd0c122 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Sep 2012 17:57:42 +0200 Subject: [PATCH 09/38] mac80211: add channel context iterator Drivers may need to iterate the active channel contexts, export an iterator function to allow that. To make it possible, use RCU-safe list functions. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 21 +++++++++++++++++++++ net/mac80211/chan.c | 22 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3560881d17ee..f12df5bb529f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3596,6 +3596,27 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, void *data), void *iter_data); +/** + * ieee80211_iter_chan_contexts_atomic - iterate channel contexts + * @hw: pointre obtained from ieee80211_alloc_hw(). + * @iter: iterator function + * @iter_data: data passed to iterator function + * + * Iterate all active channel contexts. This function is atomic and + * doesn't acquire any locks internally that might be held in other + * places while calling into the driver. + * + * The iterator will not find a context that's being added (during + * the driver callback to add it) but will find it while it's being + * removed. + */ +void ieee80211_iter_chan_contexts_atomic( + struct ieee80211_hw *hw, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf, + void *data), + void *iter_data); + /** * ieee80211_ap_probereq_get - retrieve a Probe Request template * @hw: pointer obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index bfaa486d928c..f84b86028a9c 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -3,6 +3,7 @@ */ #include +#include #include #include "ieee80211_i.h" #include "driver-ops.h" @@ -134,7 +135,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, } } - list_add(&ctx->list, &local->chanctx_list); + list_add_rcu(&ctx->list, &local->chanctx_list); return ctx; } @@ -153,7 +154,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, drv_remove_chanctx(local, ctx); } - list_del(&ctx->list); + list_del_rcu(&ctx->list); kfree_rcu(ctx, rcu_head); } @@ -379,3 +380,20 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) __ieee80211_vif_release_channel(sdata); mutex_unlock(&sdata->local->chanctx_mtx); } + +void ieee80211_iter_chan_contexts_atomic( + struct ieee80211_hw *hw, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf, + void *data), + void *iter_data) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_chanctx *ctx; + + rcu_read_lock(); + list_for_each_entry_rcu(ctx, &local->chanctx_list, list) + iter(hw, &ctx->conf, iter_data); + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic); From 700e8ea6770df3113e735bcc76ecd6ffac71a13c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:29:37 +0300 Subject: [PATCH 10/38] mac80211: Take status code as parameter to ieee80211_send_auth Non-zero status code may be needed for Authentication frames, e.g., when using SAE. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 4 ++-- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 4 ++-- net/mac80211/util.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 291c9e07f1bd..c6b1448224f2 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -279,7 +279,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, ibss_dbg(sdata, "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", sdata->vif.addr, addr, sdata->u.ibss.bssid); - ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, + ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, addr, sdata->u.ibss.bssid, NULL, 0, 0); } return sta; @@ -397,7 +397,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, * However, try to reply to authentication attempts if someone * has actually implemented this. */ - ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, + ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 132577d22928..c06219fe9094 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1531,7 +1531,7 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, } void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, - u16 transaction, u16 auth_alg, + u16 transaction, u16 auth_alg, u16 status, u8 *extra, size_t extra_len, const u8 *bssid, const u8 *da, const u8 *key, u8 key_len, u8 key_idx); void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f3f338541b01..a79bea5b93b7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1864,7 +1864,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, return; auth_data->expected_transaction = 4; drv_mgd_prepare_tx(sdata->local, sdata); - ieee80211_send_auth(sdata, 3, auth_data->algorithm, + ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, elems.challenge - 2, elems.challenge_len + 2, auth_data->bss->bssid, auth_data->bss->bssid, auth_data->key, auth_data->key_len, @@ -2762,7 +2762,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) IEEE80211_AUTH_MAX_TRIES); auth_data->expected_transaction = 2; - ieee80211_send_auth(sdata, 1, auth_data->algorithm, + ieee80211_send_auth(sdata, 1, auth_data->algorithm, 0, auth_data->ie, auth_data->ie_len, auth_data->bss->bssid, auth_data->bss->bssid, NULL, 0, 0); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b732e219b107..558412d75ac3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -978,7 +978,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, } void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, - u16 transaction, u16 auth_alg, + u16 transaction, u16 auth_alg, u16 status, u8 *extra, size_t extra_len, const u8 *da, const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) { @@ -1003,7 +1003,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); - mgmt->u.auth.status_code = cpu_to_le16(0); + mgmt->u.auth.status_code = cpu_to_le16(status); if (extra) memcpy(skb_put(skb, extra_len), extra, extra_len); From 0f4126e8918985ccc1beb936efd4b9d1e9005a63 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:29:38 +0300 Subject: [PATCH 11/38] mac80211: Add debug print on unexpect authentication state This is useful when debugging authentication process issues. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a79bea5b93b7..04334b0b6b4e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1898,8 +1898,13 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, status_code = le16_to_cpu(mgmt->u.auth.status_code); if (auth_alg != ifmgd->auth_data->algorithm || - auth_transaction != ifmgd->auth_data->expected_transaction) + auth_transaction != ifmgd->auth_data->expected_transaction) { + sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n", + mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, + auth_transaction, + ifmgd->auth_data->expected_transaction); return RX_MGMT_NONE; + } if (status_code != WLAN_STATUS_SUCCESS) { sdata_info(sdata, "%pM denied authentication (status %d)\n", From e39e5b5e7206767a0f1be0e5cb7acbd0db87ae60 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:29:39 +0300 Subject: [PATCH 12/38] cfg80211: Allow user space to specify non-IEs to SAE Authentication SAE extends Authentication frames with fields that are not information elements. NL80211_ATTR_IE is not suitable for these, so introduce a new attribute that can be used to specify the fields needed for SAE in station mode. Signed-off-by: Jouni Malinen [change to verify that SAE is only used with authenticate command] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 +++ include/uapi/linux/nl80211.h | 11 +++++++ net/wireless/core.h | 6 ++-- net/wireless/mlme.c | 11 +++++-- net/wireless/nl80211.c | 60 ++++++++++++++++++++++++++++-------- net/wireless/sme.c | 2 +- 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1b4989082244..60cebfac3e3c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1152,6 +1152,9 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); * @key_len: length of WEP key for shared key authentication * @key_idx: index of WEP key for shared key authentication * @key: WEP key for shared key authentication + * @sae_data: Non-IE data to use with SAE or %NULL. This starts with + * Authentication transaction sequence number field. + * @sae_data_len: Length of sae_data buffer in octets */ struct cfg80211_auth_request { struct cfg80211_bss *bss; @@ -1160,6 +1163,8 @@ struct cfg80211_auth_request { enum nl80211_auth_type auth_type; const u8 *key; u8 key_len, key_idx; + const u8 *sae_data; + size_t sae_data_len; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7df9b500c804..179a0c2e2f61 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1273,6 +1273,9 @@ enum nl80211_commands { * the connection request from a station. nl80211_connect_failed_reason * enum has different reasons of connection failure. * + * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts + * with the Authentication transaction sequence number field. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1530,6 +1533,8 @@ enum nl80211_attrs { NL80211_ATTR_CONN_FAILED_REASON, + NL80211_ATTR_SAE_DATA, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2489,6 +2494,7 @@ enum nl80211_bss_status { * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) + * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals * @__NL80211_AUTHTYPE_NUM: internal * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by @@ -2500,6 +2506,7 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_SHARED_KEY, NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_NETWORK_EAP, + NL80211_AUTHTYPE_SAE, /* keep last */ __NL80211_AUTHTYPE_NUM, @@ -3028,6 +3035,9 @@ enum nl80211_ap_sme_features { * in the interface combinations, even when it's only used for scan * and remain-on-channel. This could be due to, for example, the * remain-on-channel implementation requiring a channel context. + * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of + * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station + * mode */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3035,6 +3045,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, + NL80211_FEATURE_SAE = 1 << 5, }; /** diff --git a/net/wireless/core.h b/net/wireless/core.h index a343be4a52bd..b8eb743fe7da 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -320,13 +320,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx); + const u8 *key, int key_len, int key_idx, + const u8 *sae_data, int sae_data_len); int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx); + const u8 *key, int key_len, int key_idx, + const u8 *sae_data, int sae_data_len); int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8016fee0752b..460d49325741 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -273,7 +273,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx) + const u8 *key, int key_len, int key_idx, + const u8 *sae_data, int sae_data_len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; @@ -293,6 +294,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, req.ie = ie; req.ie_len = ie_len; + req.sae_data = sae_data; + req.sae_data_len = sae_data_len; req.auth_type = auth_type; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -319,7 +322,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx) + const u8 *key, int key_len, int key_idx, + const u8 *sae_data, int sae_data_len) { int err; @@ -327,7 +331,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key, key_len, key_idx); + key, key_len, key_idx, + sae_data, sae_data_len); wdev_unlock(dev->ieee80211_ptr); mutex_unlock(&rdev->devlist_mtx); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0418a6d5c1a6..74d8123ada77 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -23,7 +23,6 @@ #include "nl80211.h" #include "reg.h" -static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type); static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_crypto_settings *settings, @@ -355,6 +354,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, }; /* policy for the key attributes */ @@ -2490,6 +2490,30 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, return ret; } +static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, + enum nl80211_auth_type auth_type, + enum nl80211_commands cmd) +{ + if (auth_type > NL80211_AUTHTYPE_MAX) + return false; + + switch (cmd) { + case NL80211_CMD_AUTHENTICATE: + if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) && + auth_type == NL80211_AUTHTYPE_SAE) + return false; + return true; + case NL80211_CMD_CONNECT: + case NL80211_CMD_START_AP: + /* SAE not supported yet */ + if (auth_type == NL80211_AUTHTYPE_SAE) + return false; + return true; + default: + return false; + } +} + static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -2559,7 +2583,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { params.auth_type = nla_get_u32( info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(params.auth_type)) + if (!nl80211_valid_auth_type(rdev, params.auth_type, + NL80211_CMD_START_AP)) return -EINVAL; } else params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; @@ -4852,11 +4877,6 @@ static int nl80211_dump_survey(struct sk_buff *skb, return res; } -static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) -{ - return auth_type <= NL80211_AUTHTYPE_MAX; -} - static bool nl80211_valid_wpa_versions(u32 wpa_versions) { return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | @@ -4868,8 +4888,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; - const u8 *bssid, *ssid, *ie = NULL; - int err, ssid_len, ie_len = 0; + const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL; + int err, ssid_len, ie_len = 0, sae_data_len = 0; enum nl80211_auth_type auth_type; struct key_parse key; bool local_state_change; @@ -4945,9 +4965,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) } auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(auth_type)) + if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE)) return -EINVAL; + if (auth_type == NL80211_AUTHTYPE_SAE && + !info->attrs[NL80211_ATTR_SAE_DATA]) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_SAE_DATA]) { + if (auth_type != NL80211_AUTHTYPE_SAE) + return -EINVAL; + sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]); + sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]); + /* need to include at least Auth Transaction and Status Code */ + if (sae_data_len < 4) + return -EINVAL; + } + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; /* @@ -4959,7 +4993,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key.p.key, key.p.key_len, key.idx); + key.p.key, key.p.key_len, key.idx, + sae_data, sae_data_len); } static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, @@ -5596,7 +5631,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { connect.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(connect.auth_type)) + if (!nl80211_valid_auth_type(rdev, connect.auth_type, + NL80211_CMD_CONNECT)) return -EINVAL; } else connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 6f39cb808302..055d59643616 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -179,7 +179,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) params->ssid, params->ssid_len, NULL, 0, params->key, params->key_len, - params->key_idx); + params->key_idx, NULL, 0); case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; From 6b8ece3a7031523a05a535761108775b1b67d272 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:29:40 +0300 Subject: [PATCH 13/38] mac80211: Allow station mode SAE to be implemented in user space SAE uses two rounds of Authentication frames and both rounds require considerable calculation to be done. This commit extends the existing station mode authentication request to allow more control for user space programs to build the SAE fields and to run the authentication step ones. Only the second round with authentication transaction sequence 2 will result in moving to authenticated state. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 5 +++-- net/mac80211/main.c | 1 + net/mac80211/mlme.c | 44 +++++++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c06219fe9094..f17c41acb310 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -378,8 +378,9 @@ struct ieee80211_mgd_auth_data { u8 key_len, key_idx; bool done; - size_t ie_len; - u8 ie[]; + u16 sae_trans, sae_status; + size_t data_len; + u8 data[]; }; struct ieee80211_mgd_assoc_data { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2c8969b67851..473b755b349f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -599,6 +599,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; wiphy->features = NL80211_FEATURE_SK_TX_STATUS | + NL80211_FEATURE_SAE | NL80211_FEATURE_HT_IBSS; if (!ops->set_key) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 04334b0b6b4e..f24884a60614 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1917,6 +1917,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, case WLAN_AUTH_OPEN: case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: + case WLAN_AUTH_SAE: break; case WLAN_AUTH_SHARED_KEY: if (ifmgd->auth_data->expected_transaction != 4) { @@ -1936,6 +1937,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; run_again(ifmgd, ifmgd->auth_data->timeout); + if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && + ifmgd->auth_data->expected_transaction != 2) { + /* + * Report auth frame to user space for processing since another + * round of Authentication frames is still needed. + */ + return RX_MGMT_CFG80211_RX_AUTH; + } + /* move station state to auth */ mutex_lock(&sdata->local->sta_mtx); sta = sta_info_get(sdata, bssid); @@ -2762,13 +2772,23 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) drv_mgd_prepare_tx(local, sdata); if (auth_data->bss->proberesp_ies) { + u16 trans = 1; + u16 status = 0; + sdata_info(sdata, "send auth to %pM (try %d/%d)\n", auth_data->bss->bssid, auth_data->tries, IEEE80211_AUTH_MAX_TRIES); auth_data->expected_transaction = 2; - ieee80211_send_auth(sdata, 1, auth_data->algorithm, 0, - auth_data->ie, auth_data->ie_len, + + if (auth_data->algorithm == WLAN_AUTH_SAE) { + trans = auth_data->sae_trans; + status = auth_data->sae_status; + auth_data->expected_transaction = trans; + } + + ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, + auth_data->data, auth_data->data_len, auth_data->bss->bssid, auth_data->bss->bssid, NULL, 0, 0); } else { @@ -3329,19 +3349,33 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, case NL80211_AUTHTYPE_NETWORK_EAP: auth_alg = WLAN_AUTH_LEAP; break; + case NL80211_AUTHTYPE_SAE: + auth_alg = WLAN_AUTH_SAE; + break; default: return -EOPNOTSUPP; } - auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL); + auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len + + req->ie_len, GFP_KERNEL); if (!auth_data) return -ENOMEM; auth_data->bss = req->bss; + if (req->sae_data_len >= 4) { + __le16 *pos = (__le16 *) req->sae_data; + auth_data->sae_trans = le16_to_cpu(pos[0]); + auth_data->sae_status = le16_to_cpu(pos[1]); + memcpy(auth_data->data, req->sae_data + 4, + req->sae_data_len - 4); + auth_data->data_len += req->sae_data_len - 4; + } + if (req->ie && req->ie_len) { - memcpy(auth_data->ie, req->ie, req->ie_len); - auth_data->ie_len = req->ie_len; + memcpy(&auth_data->data[auth_data->data_len], + req->ie, req->ie_len); + auth_data->data_len += req->ie_len; } if (req->key && req->key_len) { From eea57d42fb148a078ebc2f54731b580fb9edeaf7 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 8 Oct 2012 21:33:47 +0530 Subject: [PATCH 14/38] mac80211: Use appropriate debug wrapper ieee80211_sta_expire will be called by both IBSS and mesh interfaces to account for inactive stations, so it would be more appropriate to use sta_dbg instead of ibss_dbg. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fa639f41aa5b..d5a5d62b6b0c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -893,8 +893,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, continue; if (time_after(jiffies, sta->last_rx + exp_time)) { - ibss_dbg(sdata, "expiring inactive STA %pM\n", - sta->sta.addr); + sta_dbg(sta->sdata, "expiring inactive STA %pM\n", + sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); } } From 1258d97616fdca9abc0c21f2edeb1d5b21dcb128 Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Tue, 9 Oct 2012 13:27:47 -0700 Subject: [PATCH 15/38] mac80211: move out the non-statistics variable estab_plinks from mesh_stat estab_plinks is not a statistics member. Hence move estab_plinks from struct mesh_stat to struct ieee80211_if_mesh Signed-off-by: Ashok Nagarajan Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mesh.c | 2 +- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_plink.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 34e173976573..8802b8d7be13 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -471,7 +471,7 @@ IEEE80211_IF_FILE(dropped_frames_congestion, u.mesh.mshstats.dropped_frames_congestion, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, u.mesh.mshstats.dropped_frames_no_route, DEC); -IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); +IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC); /* Mesh parameters */ IEEE80211_IF_FILE(dot11MeshMaxRetries, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f17c41acb310..b7382454d0a6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -316,7 +316,6 @@ struct mesh_stats { __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ __u32 dropped_frames_no_route; /* Not transmitted, no route found */ __u32 dropped_frames_congestion;/* Not forwarded due to congestion */ - atomic_t estab_plinks; }; #define PREQ_Q_F_START 0x1 @@ -599,6 +598,7 @@ struct ieee80211_if_mesh { int preq_queue_len; struct mesh_stats mshstats; struct mesh_config mshcfg; + atomic_t estab_plinks; u32 mesh_seqnum; bool accepting_plinks; int num_gates; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 19725e0a051a..5bed4fd5ee19 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -264,7 +264,7 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) /* Authentication Protocol identifier */ *pos++ = ifmsh->mesh_auth_id; /* Mesh Formation Info - number of neighbors */ - neighbors = atomic_read(&ifmsh->mshstats.estab_plinks); + neighbors = atomic_read(&ifmsh->estab_plinks); /* Number of neighbor mesh STAs or 15 whichever is smaller */ neighbors = (neighbors > 15) ? 15 : neighbors; *pos++ = neighbors << 1; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 25d0f17dec71..8334e9445195 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -324,7 +324,7 @@ extern int mesh_allocated; static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) { return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks - - atomic_read(&sdata->u.mesh.mshstats.estab_plinks); + atomic_read(&sdata->u.mesh.estab_plinks); } static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8a8b459610b6..234fe755968b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -50,14 +50,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, static inline u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) { - atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); + atomic_inc(&sdata->u.mesh.estab_plinks); return mesh_accept_plinks_update(sdata); } static inline u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) { - atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); + atomic_dec(&sdata->u.mesh.estab_plinks); return mesh_accept_plinks_update(sdata); } From d4950281d72d8845225e3a39dbeb366c40c824c9 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Wed, 10 Oct 2012 11:25:40 +0000 Subject: [PATCH 16/38] ieee80211: Rename VHT cap struct Rename struct ieee80211_vht_capabilities to ieee80211_vht_cap and renamed its member vht_capabilities_info to vht_cap_info. Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 45 +++++++++++++++++++++++++++------------ net/mac80211/main.c | 2 +- net/mac80211/mlme.c | 4 ++-- net/mac80211/util.c | 4 ++-- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 2385119f8bb0..8c803f0e4925 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1107,20 +1107,6 @@ struct ieee80211_ht_operation { #define WLAN_HT_SMPS_CONTROL_STATIC 1 #define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 -#define VHT_MCS_SUPPORTED_SET_SIZE 8 - -struct ieee80211_vht_capabilities { - __le32 vht_capabilities_info; - u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE]; -} __packed; - -struct ieee80211_vht_operation { - u8 vht_op_info_chwidth; - u8 vht_op_info_chan_center_freq_seg1_idx; - u8 vht_op_info_chan_center_freq_seg2_idx; - __le16 vht_basic_mcs_set; -} __packed; - /** * struct ieee80211_vht_mcs_info - VHT MCS information * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams @@ -1141,6 +1127,37 @@ struct ieee80211_vht_mcs_info { __le16 tx_highest; } __packed; +/** + * struct ieee80211_vht_cap - VHT capabilities + * + * This structure is the "VHT capabilities element" as + * described in 802.11ac D3.0 8.4.2.160 + * @vht_cap_info: VHT capability info + * @supp_mcs: VHT MCS supported rates + */ +struct ieee80211_vht_cap { + __le32 vht_cap_info; + struct ieee80211_vht_mcs_info supp_mcs; +} __packed; + +/** + * struct ieee80211_vht_operation - VHT operation IE + * + * This structure is the "VHT operation element" as + * described in 802.11ac D3.0 8.4.2.161 + * @chan_width: Operating channel width + * @center_freq_seg1_idx: center freq segment 1 index + * @center_freq_seg2_idx: center freq segment 2 index + * @basic_mcs_set: VHT Basic MCS rate set + */ +struct ieee80211_vht_operation { + u8 chan_width; + u8 center_freq_seg1_idx; + u8 center_freq_seg2_idx; + __le16 basic_mcs_set; +} __packed; + + #define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0 #define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1 #define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2 diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 473b755b349f..620f427069c8 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -876,7 +876,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (supp_vht) local->scan_ies_len += - 2 + sizeof(struct ieee80211_vht_capabilities); + 2 + sizeof(struct ieee80211_vht_cap); if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f24884a60614..4af5a3eb892e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -353,7 +353,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, cap = vht_cap.cap; /* reserve and fill IE */ - pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); } @@ -412,7 +412,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) 4 + /* power capability */ 2 + 2 * sband->n_channels + /* supported channels */ 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ - 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ + 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ assoc_data->ie_len + /* extra IEs */ 9, /* WMM */ GFP_KERNEL); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 558412d75ac3..3dca9827624a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1775,8 +1775,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, __le32 tmp; *pos++ = WLAN_EID_VHT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_vht_capabilities); - memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); + *pos++ = sizeof(struct ieee80211_vht_cap); + memset(pos, 0, sizeof(struct ieee80211_vht_cap)); /* capability flags */ tmp = cpu_to_le32(cap); From 818255ea47709065c53c86ca47fce96d8580bee1 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Wed, 10 Oct 2012 11:33:04 +0000 Subject: [PATCH 17/38] mac80211: VHT peer STA caps Save the AP's VHT capabilities (in managed mode) and make them available to the driver in the station information. Unlike HT capabilities, they aren't restricted to the common capabilities, so drivers must be aware of their own capabilities. Signed-off-by: Mahesh Palivela [fix endian conversion bug ...] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/Makefile | 1 + net/mac80211/ieee80211_i.h | 7 +++++++ net/mac80211/mlme.c | 5 +++++ net/mac80211/util.c | 12 ++++++++++++ net/mac80211/vht.c | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+) create mode 100644 net/mac80211/vht.c diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f12df5bb529f..89d5bba28e05 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1122,6 +1122,8 @@ enum ieee80211_sta_state { * @aid: AID we assigned to the station if we're an AP * @supp_rates: Bitmap of supported rates (per band) * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities + * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities + * of remote STA. Taking as is. * @wme: indicates whether the STA supports WME. Only valid during AP-mode. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. @@ -1134,6 +1136,7 @@ struct ieee80211_sta { u8 addr[ETH_ALEN]; u16 aid; struct ieee80211_sta_ht_cap ht_cap; + struct ieee80211_sta_vht_cap vht_cap; bool wme; u8 uapsd_queues; u8 max_sp; diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a7dd110faafa..4911202334d9 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -8,6 +8,7 @@ mac80211-y := \ wpa.o \ scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ + vht.o \ ibss.o \ iface.o \ rate.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b7382454d0a6..6327816790e6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1188,6 +1188,8 @@ struct ieee802_11_elems { u8 *wmm_param; struct ieee80211_ht_cap *ht_cap_elem; struct ieee80211_ht_operation *ht_operation; + struct ieee80211_vht_cap *vht_cap_elem; + struct ieee80211_vht_operation *vht_operation; struct ieee80211_meshconf_ie *mesh_config; u8 *mesh_id; u8 *peering; @@ -1416,6 +1418,11 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); +/* VHT */ +void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct ieee80211_vht_cap *vht_cap_ie, + struct ieee80211_sta_vht_cap *vht_cap); /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4af5a3eb892e..ab39c4f44e5c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2156,6 +2156,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->supports_40mhz = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) + ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, + elems.vht_cap_elem, + &sta->sta.vht_cap); + rate_control_rate_init(sta); if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3dca9827624a..51a4a2516233 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -741,6 +741,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, else elem_parse_failed = true; break; + case WLAN_EID_VHT_CAPABILITY: + if (elen >= sizeof(struct ieee80211_vht_cap)) + elems->vht_cap_elem = (void *)pos; + else + elem_parse_failed = true; + break; + case WLAN_EID_VHT_OPERATION: + if (elen >= sizeof(struct ieee80211_vht_operation)) + elems->vht_operation = (void *)pos; + else + elem_parse_failed = true; + break; case WLAN_EID_MESH_ID: elems->mesh_id = pos; elems->mesh_id_len = elen; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c new file mode 100644 index 000000000000..f311388aeedf --- /dev/null +++ b/net/mac80211/vht.c @@ -0,0 +1,35 @@ +/* + * VHT handling + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include "ieee80211_i.h" + + +void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct ieee80211_vht_cap *vht_cap_ie, + struct ieee80211_sta_vht_cap *vht_cap) +{ + if (WARN_ON_ONCE(!vht_cap)) + return; + + memset(vht_cap, 0, sizeof(*vht_cap)); + + if (!vht_cap_ie || !sband->vht_cap.vht_supported) + return; + + vht_cap->vht_supported = true; + + vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); + + /* Copy peer MCS info, the driver might need them. */ + memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, + sizeof(struct ieee80211_vht_mcs_info)); +} From f461be3eff662f01a177ecea8c1d7b040bb6bfbe Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Thu, 11 Oct 2012 08:04:52 +0000 Subject: [PATCH 18/38] {nl,cfg}80211: Peer STA VHT caps To save STAs VHT caps in AP mode Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ include/uapi/linux/nl80211.h | 6 ++++++ net/mac80211/cfg.c | 5 +++++ net/wireless/nl80211.c | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 60cebfac3e3c..607b5c02f740 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -498,6 +498,7 @@ enum station_parameters_apply_mask { * @plink_action: plink action to take * @plink_state: set the peer link state for a station * @ht_capa: HT capabilities of station + * @vht_capa: VHT capabilities of station * @uapsd_queues: bitmap of queues configured for uapsd. same format * as the AC bitmap in the QoS info field * @max_sp: max Service Period. same format as the MAX_SP in the @@ -517,6 +518,7 @@ struct station_parameters { u8 plink_action; u8 plink_state; struct ieee80211_ht_cap *ht_capa; + struct ieee80211_vht_cap *vht_capa; u8 uapsd_queues; u8 max_sp; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 179a0c2e2f61..71ab23b0356d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1276,6 +1276,9 @@ enum nl80211_commands { * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts * with the Authentication transaction sequence number field. * + * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1535,6 +1538,8 @@ enum nl80211_attrs { NL80211_ATTR_SAE_DATA, + NL80211_ATTR_VHT_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1578,6 +1583,7 @@ enum nl80211_attrs { #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 +#define NL80211_VHT_CAPABILITY_LEN 12 #define NL80211_MAX_NR_CIPHER_SUITES 5 #define NL80211_MAX_NR_AKM_SUITES 2 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03216b0408c7..ed27988f9d35 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1157,6 +1157,11 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->ht_capa, &sta->sta.ht_cap); + if (params->vht_capa) + ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, + params->vht_capa, + &sta->sta.vht_cap); + if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 74d8123ada77..ef170e982f91 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -355,6 +355,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, + [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, }; /* policy for the key attributes */ @@ -3223,6 +3224,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) + params.vht_capa = + nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); From ed47377154310fd2fd59d75fcdeb3d022344fb31 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Thu, 11 Oct 2012 21:03:31 -0700 Subject: [PATCH 19/38] {nl,cfg}80211: add a flags word to scan requests Add a flags word to direct and scheduled scan requests; it will be used for control of optional behaviours such as flushing the bss cache prior to doing a scan. Signed-off-by: Sam Leffler Tested-by: Amitkumar Karwar Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 15 +++++++++++++++ net/wireless/nl80211.c | 12 ++++++++++++ 3 files changed, 31 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 607b5c02f740..d95da8f55f6e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1002,6 +1002,7 @@ struct cfg80211_ssid { * @n_channels: total number of channels to scan * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets + * @flags: bit field of flags controlling operation * @rates: bitmap of rates to advertise for each band * @wiphy: the wiphy this was for * @wdev: the wireless device to scan for @@ -1014,6 +1015,7 @@ struct cfg80211_scan_request { u32 n_channels; const u8 *ie; size_t ie_len; + u32 flags; u32 rates[IEEE80211_NUM_BANDS]; @@ -1046,6 +1048,7 @@ struct cfg80211_match_set { * @interval: interval between each scheduled scan cycle * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets + * @flags: bit field of flags controlling operation * @match_sets: sets of parameters to be matched for a scan result * entry to be considered valid and to be passed to the host * (others are filtered out). @@ -1063,6 +1066,7 @@ struct cfg80211_sched_scan_request { u32 interval; const u8 *ie; size_t ie_len; + u32 flags; struct cfg80211_match_set *match_sets; int n_match_sets; s32 rssi_thold; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 71ab23b0356d..4d0b49ee4c2c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1279,6 +1279,8 @@ enum nl80211_commands { * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) * + * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32) + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1540,6 +1542,8 @@ enum nl80211_attrs { NL80211_ATTR_VHT_CAPABILITY, + NL80211_ATTR_SCAN_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3086,4 +3090,15 @@ enum nl80211_connect_failed_reason { NL80211_CONN_FAIL_BLOCKED_CLIENT, }; +/** + * enum nl80211_scan_flags - scan request control flags + * + * Scan request control flags are used to control the handling + * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN + * requests. + * (will be filled) +enum nl80211_scan_flags { +}; + */ + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ef170e982f91..dc08211c6c6b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -356,6 +356,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, + [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -4367,6 +4368,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) } } + if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) + request->flags = nla_get_u32( + info->attrs[NL80211_ATTR_SCAN_FLAGS]); + request->no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); @@ -4598,6 +4603,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->ie_len); } + if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) + request->flags = nla_get_u32( + info->attrs[NL80211_ATTR_SCAN_FLAGS]); + request->dev = dev; request->wiphy = &rdev->wiphy; request->interval = interval; @@ -7663,6 +7672,9 @@ static int nl80211_add_scan_req(struct sk_buff *msg, nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie)) goto nla_put_failure; + if (req->flags) + nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags); + return 0; nla_put_failure: return -ENOBUFS; From e8e27c668bf5977d9fe1a64d0b69598ff9e292b7 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 11 Oct 2012 21:03:33 -0700 Subject: [PATCH 20/38] cfg80211: code rearrangement to avoid forward declarations bss_release() and __cfg80211_unlink_bss() function definitions are moved at the begining of the file. They are used in next patch in this series. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Johannes Berg --- net/wireless/scan.c | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9730c9862bdc..20050965abca 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -20,6 +20,33 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) +static void bss_release(struct kref *ref) +{ + struct cfg80211_internal_bss *bss; + + bss = container_of(ref, struct cfg80211_internal_bss, ref); + if (bss->pub.free_priv) + bss->pub.free_priv(&bss->pub); + + if (bss->beacon_ies_allocated) + kfree(bss->pub.beacon_ies); + if (bss->proberesp_ies_allocated) + kfree(bss->pub.proberesp_ies); + + BUG_ON(atomic_read(&bss->hold)); + + kfree(bss); +} + +/* must hold dev->bss_lock! */ +static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *bss) +{ + list_del_init(&bss->list); + rb_erase(&bss->rbn, &dev->bss_tree); + kref_put(&bss->ref, bss_release); +} + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; @@ -158,24 +185,6 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, return 0; } -static void bss_release(struct kref *ref) -{ - struct cfg80211_internal_bss *bss; - - bss = container_of(ref, struct cfg80211_internal_bss, ref); - if (bss->pub.free_priv) - bss->pub.free_priv(&bss->pub); - - if (bss->beacon_ies_allocated) - kfree(bss->pub.beacon_ies); - if (bss->proberesp_ies_allocated) - kfree(bss->pub.proberesp_ies); - - BUG_ON(atomic_read(&bss->hold)); - - kfree(bss); -} - /* must hold dev->bss_lock! */ void cfg80211_bss_age(struct cfg80211_registered_device *dev, unsigned long age_secs) @@ -188,15 +197,6 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, } } -/* must hold dev->bss_lock! */ -static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *bss) -{ - list_del_init(&bss->list); - rb_erase(&bss->rbn, &dev->bss_tree); - kref_put(&bss->ref, bss_release); -} - /* must hold dev->bss_lock! */ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) { From 46856bbf0f0412c12e9674df68822cb531d49327 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Thu, 11 Oct 2012 21:03:32 -0700 Subject: [PATCH 21/38] cfg80211: add scan flag to indicate its priority Add NL80211_SCAN_FLAG_LOW_PRIORITY flag support. It tells drivers that this is a low priority scan request, so that they can take necessary action. Drivers need to advertise low priority scan capability during registration. Signed-off-by: Sam Leffler Tested-by: Amitkumar Karwar Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 8 ++++++-- net/wireless/nl80211.c | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 4d0b49ee4c2c..c68e15e41321 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3048,6 +3048,7 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station * mode + * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3056,6 +3057,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, NL80211_FEATURE_SAE = 1 << 5, + NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, }; /** @@ -3096,9 +3098,11 @@ enum nl80211_connect_failed_reason { * Scan request control flags are used to control the handling * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN * requests. - * (will be filled) + * + * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority + */ enum nl80211_scan_flags { + NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, }; - */ #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dc08211c6c6b..aee252d65b8f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4368,9 +4368,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) } } - if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) + if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + err = -EOPNOTSUPP; + goto out_free; + } + } request->no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); @@ -4603,9 +4609,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->ie_len); } - if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) + if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + err = -EOPNOTSUPP; + goto out_free; + } + } request->dev = dev; request->wiphy = &rdev->wiphy; From b292219fa5061e2657ecf518b48426913d0ddae6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Oct 2012 10:55:53 +0200 Subject: [PATCH 22/38] wireless: use OR operation to set wiphy features The next patch will introduce a flag that is set by default in cfg80211 so drivers and mac80211 need to use |= to set features they have so that they don't clear the already-set feature. We could set the flag in wiphy_register() instead of wiphy_new() to avoid this patch, but then the drivers couldn't *unset* flags they don't want to use even though the implementation is generic. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++-- net/mac80211/main.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 7089f8160ad5..99a75d92c6cf 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3651,7 +3651,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, ar->fw_capabilities)) - ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER; + ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 0679458a1bac..38a58713de6a 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2250,8 +2250,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; - wiphy->features = NL80211_FEATURE_HT_IBSS | - NL80211_FEATURE_INACTIVITY_TIMER; + wiphy->features |= NL80211_FEATURE_HT_IBSS | + NL80211_FEATURE_INACTIVITY_TIMER; /* Reserve space for mwifiex specific private data for BSS */ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 620f427069c8..931f14f3281f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -598,9 +598,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (ops->remain_on_channel) wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->features = NL80211_FEATURE_SK_TX_STATUS | - NL80211_FEATURE_SAE | - NL80211_FEATURE_HT_IBSS; + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | + NL80211_FEATURE_SAE | + NL80211_FEATURE_HT_IBSS; if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; From 15d6030b4bec618742b8b9ccae9209c8f9e4a916 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Thu, 11 Oct 2012 21:03:34 -0700 Subject: [PATCH 23/38] cfg80211: add support for flushing old scan results Add an NL80211_SCAN_FLAG_FLUSH flag that causes old bss cache entries to be flushed on scan completion. This is useful for collecting guaranteed fresh scan/survey result (e.g. on resume). For normal scan, flushing only happens on successful completion of a scan; i.e. it does not happen if the scan is aborted. For scheduled scan, previous scan results are flushed everytime when we get new scan results. This feature is enabled by default. Drivers can disable it by unsetting the NL80211_FEATURE_SCAN_FLUSH flag. Signed-off-by: Sam Leffler Tested-by: Amitkumar Karwar Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao [invert polarity of feature flag to account for old kernels] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 ++ include/uapi/linux/nl80211.h | 4 +++ net/wireless/core.c | 2 ++ net/wireless/nl80211.c | 14 +++++--- net/wireless/scan.c | 66 +++++++++++++++++++++++++----------- net/wireless/sme.c | 1 + 6 files changed, 66 insertions(+), 24 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d95da8f55f6e..aa0e4a12308c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1005,6 +1005,7 @@ struct cfg80211_ssid { * @flags: bit field of flags controlling operation * @rates: bitmap of rates to advertise for each band * @wiphy: the wiphy this was for + * @scan_start: time (in jiffies) when the scan started * @wdev: the wireless device to scan for * @aborted: (internal) scan request was notified as aborted * @no_cck: used to send probe requests at non CCK rate in 2GHz band @@ -1023,6 +1024,7 @@ struct cfg80211_scan_request { /* internal */ struct wiphy *wiphy; + unsigned long scan_start; bool aborted; bool no_cck; @@ -1074,6 +1076,7 @@ struct cfg80211_sched_scan_request { /* internal */ struct wiphy *wiphy; struct net_device *dev; + unsigned long scan_start; /* keep last */ struct ieee80211_channel *channels[0]; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c68e15e41321..0e6277a06c29 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3049,6 +3049,7 @@ enum nl80211_ap_sme_features { * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station * mode * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan + * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3058,6 +3059,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, NL80211_FEATURE_SAE = 1 << 5, NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, + NL80211_FEATURE_SCAN_FLUSH = 1 << 7, }; /** @@ -3100,9 +3102,11 @@ enum nl80211_connect_failed_reason { * requests. * * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority + * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, + NL80211_SCAN_FLAG_FLUSH = 1<<1, }; #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 443d4d7deea2..48c2ea4712e9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -370,6 +370,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.rts_threshold = (u32) -1; rdev->wiphy.coverage_class = 0; + rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; + return &rdev->wiphy; } EXPORT_SYMBOL(wiphy_new); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aee252d65b8f..9e5a7206b0b4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4371,8 +4371,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); - if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || + ((request->flags & NL80211_SCAN_FLAG_FLUSH) && + !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { err = -EOPNOTSUPP; goto out_free; } @@ -4383,6 +4385,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->wdev = wdev; request->wiphy = &rdev->wiphy; + request->scan_start = jiffies; rdev->scan_req = request; err = rdev->ops->scan(&rdev->wiphy, request); @@ -4612,8 +4615,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { request->flags = nla_get_u32( info->attrs[NL80211_ATTR_SCAN_FLAGS]); - if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || + ((request->flags & NL80211_SCAN_FLAG_FLUSH) && + !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { err = -EOPNOTSUPP; goto out_free; } @@ -4622,6 +4627,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->dev = dev; request->wiphy = &rdev->wiphy; request->interval = interval; + request->scan_start = jiffies; err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); if (!err) { diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 20050965abca..a8d5a9a07e49 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -47,6 +47,27 @@ static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, kref_put(&bss->ref, bss_release); } +/* must hold dev->bss_lock! */ +static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, + unsigned long expire_time) +{ + struct cfg80211_internal_bss *bss, *tmp; + bool expired = false; + + list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { + if (atomic_read(&bss->hold)) + continue; + if (!time_after(expire_time, bss->ts)) + continue; + + __cfg80211_unlink_bss(dev, bss); + expired = true; + } + + if (expired) + dev->bss_generation++; +} + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; @@ -72,10 +93,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) if (wdev->netdev) cfg80211_sme_scan_done(wdev->netdev); - if (request->aborted) + if (request->aborted) { nl80211_send_scan_aborted(rdev, wdev); - else + } else { + if (request->flags & NL80211_SCAN_FLAG_FLUSH) { + /* flush entries from previous scans */ + spin_lock_bh(&rdev->bss_lock); + __cfg80211_bss_expire(rdev, request->scan_start); + spin_unlock_bh(&rdev->bss_lock); + } nl80211_send_scan_done(rdev, wdev); + } #ifdef CONFIG_CFG80211_WEXT if (wdev->netdev && !request->aborted) { @@ -126,16 +154,27 @@ EXPORT_SYMBOL(cfg80211_scan_done); void __cfg80211_sched_scan_results(struct work_struct *wk) { struct cfg80211_registered_device *rdev; + struct cfg80211_sched_scan_request *request; rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); + request = rdev->sched_scan_req; + mutex_lock(&rdev->sched_scan_mtx); /* we don't have sched_scan_req anymore if the scan is stopping */ - if (rdev->sched_scan_req) - nl80211_send_sched_scan_results(rdev, - rdev->sched_scan_req->dev); + if (request) { + if (request->flags & NL80211_SCAN_FLAG_FLUSH) { + /* flush entries from previous scans */ + spin_lock_bh(&rdev->bss_lock); + __cfg80211_bss_expire(rdev, request->scan_start); + spin_unlock_bh(&rdev->bss_lock); + request->scan_start = + jiffies + msecs_to_jiffies(request->interval); + } + nl80211_send_sched_scan_results(rdev, request->dev); + } mutex_unlock(&rdev->sched_scan_mtx); } @@ -197,23 +236,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, } } -/* must hold dev->bss_lock! */ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) { - struct cfg80211_internal_bss *bss, *tmp; - bool expired = false; - - list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { - if (atomic_read(&bss->hold)) - continue; - if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) - continue; - __cfg80211_unlink_bss(dev, bss); - expired = true; - } - - if (expired) - dev->bss_generation++; + __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); } const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) @@ -962,6 +987,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->ssids = (void *)&creq->channels[n_channels]; creq->n_channels = n_channels; creq->n_ssids = 1; + creq->scan_start = jiffies; /* translate "Scan on frequencies" request */ i = 0; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 055d59643616..07d717eb9e2a 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -138,6 +138,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) request->wdev = wdev; request->wiphy = &rdev->wiphy; + request->scan_start = jiffies; rdev->scan_req = request; From cd2bb512cda58f1efb922ad6dc29013ea5d5d9d0 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Thu, 11 Oct 2012 21:03:35 -0700 Subject: [PATCH 24/38] mac80211: add support for tx to abort low priority scan requests Use NL80211_SCAN_FLAG_LOW_PRIORITY flag in mac80211's scan state machine to prematurely terminate scan operations if outbound traffic collides. This is useful for marking background scans so they don't affect throughput. Signed-off-by: Sam Leffler Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao [set feature flag only if software scan is used] Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/main.c | 3 +++ net/mac80211/scan.c | 21 +++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6327816790e6..02e47930964f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -866,6 +866,7 @@ enum { * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to * send out data * @SCAN_RESUME: Resume the scan and scan the next channel + * @SCAN_ABORT: Abort the scan and go back to operating channel */ enum mac80211_scan_state { SCAN_DECISION, @@ -873,6 +874,7 @@ enum mac80211_scan_state { SCAN_SEND_PROBE, SCAN_SUSPEND, SCAN_RESUME, + SCAN_ABORT, }; struct ieee80211_local { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 931f14f3281f..ba5a23249771 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -602,6 +602,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NL80211_FEATURE_SAE | NL80211_FEATURE_HT_IBSS; + if (!ops->hw_scan) + wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN; + if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 987c75d46bc0..13d23299e696 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -466,6 +466,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]); local->hw_scan_req->ie = ies; + local->hw_scan_req->flags = req->flags; local->hw_scan_band = 0; @@ -566,6 +567,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long min_beacon_int = 0; struct ieee80211_sub_if_data *sdata; struct ieee80211_channel *next_chan; + enum mac80211_scan_state next_scan_state; /* * check if at least one STA interface is associated, @@ -624,10 +626,18 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, usecs_to_jiffies(min_beacon_int * 1024) * local->hw.conf.listen_interval); - if (associated && (!tx_empty || bad_latency || listen_int_exceeded)) - local->next_scan_state = SCAN_SUSPEND; - else - local->next_scan_state = SCAN_SET_CHANNEL; + if (associated && !tx_empty) { + if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) + next_scan_state = SCAN_ABORT; + else + next_scan_state = SCAN_SUSPEND; + } else if (associated && (bad_latency || listen_int_exceeded)) { + next_scan_state = SCAN_SUSPEND; + } else { + next_scan_state = SCAN_SET_CHANNEL; + } + + local->next_scan_state = next_scan_state; *next_delay = 0; } @@ -798,6 +808,9 @@ void ieee80211_scan_work(struct work_struct *work) case SCAN_RESUME: ieee80211_scan_state_resume(local, &next_delay); break; + case SCAN_ABORT: + aborted = true; + goto out_complete; } } while (next_delay == 0); From c13a765bd96f4e2f52d218ee6e5c0715380eeeb8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 12 Oct 2012 17:35:45 +0530 Subject: [PATCH 25/38] mac80211: Notify new IBSS network creation Initialization of beacon transmission in IBSS mode depends on whether a new BSS is being created or joined. When joining an existing IBSS network, beaconing has to start only after a TSF-sync has happened - this is explained in 11.1.4. Introduce a new parameter in the BSS information structure to indicate creator/joiner mode. Signed-off-by: Sujith Manoharan Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/ibss.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 89d5bba28e05..71c2f9c2f5be 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -258,6 +258,7 @@ enum ieee80211_rssi_event { * @assoc: association status * @ibss_joined: indicates whether this station is part of an IBSS * or not + * @ibss_creator: indicates if a new IBSS network is being created * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble; @@ -313,6 +314,7 @@ struct ieee80211_bss_conf { const u8 *bssid; /* association related data */ bool assoc, ibss_joined; + bool ibss_creator; u16 aid; /* erp related data */ bool use_cts_prot; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c6b1448224f2..3d5332e367f8 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -38,7 +38,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, const u8 *bssid, const int beacon_int, struct ieee80211_channel *chan, const u32 basic_rates, - const u16 capability, u64 tsf) + const u16 capability, u64 tsf, + bool creator) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; @@ -71,6 +72,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, /* if merging, indicate to driver that we leave the old IBSS */ if (sdata->vif.bss_conf.ibss_joined) { sdata->vif.bss_conf.ibss_joined = false; + sdata->vif.bss_conf.ibss_creator = false; netif_carrier_off(sdata->dev); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS); } @@ -197,6 +199,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, bss_change |= BSS_CHANGED_HT; bss_change |= BSS_CHANGED_IBSS; sdata->vif.bss_conf.ibss_joined = true; + sdata->vif.bss_conf.ibss_creator = creator; ieee80211_bss_info_change_notify(sdata, bss_change); ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); @@ -249,7 +252,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, cbss->channel, basic_rates, cbss->capability, - cbss->tsf); + cbss->tsf, + false); } static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, @@ -734,7 +738,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, ifibss->channel, ifibss->basic_rates, - capability, 0); + capability, 0, true); } /* @@ -1198,6 +1202,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) lockdep_is_held(&sdata->u.ibss.mtx)); RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); sdata->vif.bss_conf.ibss_joined = false; + sdata->vif.bss_conf.ibss_creator = false; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_IBSS); synchronize_rcu(); From 04b2312a683537eec3dbac013920b0e3cfc06123 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 12 Oct 2012 12:28:14 +0200 Subject: [PATCH 26/38] wireless: drivers: make use of WLAN_EID_VENDOR_SPECIFIC The include file linux/ieee80211.h contains three definitions for the same thing in enum ieee80211_eid due to historic changes: /* Information Element IDs */ enum ieee80211_eid { : WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, : }; The standard refers to this as "vendor specific" element so the other two definitions are better not used. This patch changes the wireless drivers to use one definition, ie. WLAN_EID_VENDOR_SPECIFIC. Cc: Jouni Malinen Cc: Dan Williams Cc: Larry Finger Acked-by: Kalle Valo [ath6kl] Acked-by: Bing Zhao [mwifiex] Acked-by: Stanislav Yakovlev [ipw2x00] Signed-off-by: Arend van Spriel [change libipw as well] Signed-off-by: Johannes Berg --- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- drivers/net/wireless/hostap/hostap_80211_rx.c | 2 +- drivers/net/wireless/ipw2x00/libipw_rx.c | 6 +++--- drivers/net/wireless/libertas/mesh.c | 2 +- drivers/net/wireless/mwifiex/scan.c | 13 ++++++++----- drivers/net/wireless/mwifiex/sta_ioctl.c | 4 ++-- drivers/net/wireless/orinoco/main.h | 2 +- 9 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 3cd05a7173f6..57f7db1ac31b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7433,7 +7433,7 @@ static inline char *airo_translate_scan(struct net_device *dev, num_null_ies++; break; - case WLAN_EID_GENERIC: + case WLAN_EID_VENDOR_SPECIFIC: if (ie[1] >= 4 && ie[2] == 0x00 && ie[3] == 0x50 && diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 99a75d92c6cf..277089963eb4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -301,7 +301,7 @@ static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif) static bool ath6kl_is_wpa_ie(const u8 *pos) { - return pos[0] == WLAN_EID_WPA && pos[1] >= 4 && + return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 && pos[5] == 0x01; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index c1abaa6db59e..0e952092ee8f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2679,7 +2679,7 @@ brcmf_find_wpaie(u8 *parse, u32 len) { struct brcmf_tlv *ie; - while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_WPA))) { + while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) return (struct brcmf_vs_tlv *)ie; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index df7050abe717..d39e3e24077b 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -415,7 +415,7 @@ static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, ssid = pos + 2; ssid_len = pos[1]; break; - case WLAN_EID_GENERIC: + case WLAN_EID_VENDOR_SPECIFIC: if (pos[1] >= 4 && pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 && pos[5] == 1) { diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index 02e057923236..95a1ca1e895c 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -1108,7 +1108,7 @@ static const char *get_info_element_string(u16 id) MFIE_STRING(ERP_INFO); MFIE_STRING(RSN); MFIE_STRING(EXT_SUPP_RATES); - MFIE_STRING(GENERIC); + MFIE_STRING(VENDOR_SPECIFIC); MFIE_STRING(QOS_PARAMETER); default: return "UNKNOWN"; @@ -1248,8 +1248,8 @@ static int libipw_parse_info_param(struct libipw_info_element LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); break; - case WLAN_EID_GENERIC: - LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n", + case WLAN_EID_VENDOR_SPECIFIC: + LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n", info_element->len); if (!libipw_parse_qos_info_param_IE(info_element, network)) diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 97807751ebcf..3e81264db81e 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -101,7 +101,7 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, switch (action) { case CMD_ACT_MESH_CONFIG_START: - ie->id = WLAN_EID_GENERIC; + ie->id = WLAN_EID_VENDOR_SPECIFIC; ie->val.oui[0] = 0x00; ie->val.oui[1] = 0x50; ie->val.oui[2] = 0x43; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 00b658d3b6ec..5896b1fb4a2d 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -153,7 +153,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == - WLAN_EID_WPA))) { + WLAN_EID_VENDOR_SPECIFIC))) { iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; oui = &mwifiex_wpa_oui[cipher][0]; ret = mwifiex_search_oui_in_ie(iebody, oui); @@ -202,7 +202,7 @@ mwifiex_is_bss_no_sec(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != - WLAN_EID_WPA)) && + WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && @@ -237,7 +237,8 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv, { if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) && - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA)) + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)) /* * Privacy bit may NOT be set in some APs like * LinkSys WRT54G && bss_desc->privacy @@ -309,7 +310,8 @@ mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) && + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && !priv->sec_info.encryption_mode && bss_desc->privacy) { @@ -329,7 +331,8 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) && + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && priv->sec_info.encryption_mode && bss_desc->privacy) { diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 0c9f70b2cbe6..552d72ed055a 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -713,7 +713,7 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len, priv->wpa_ie[0]); - if (priv->wpa_ie[0] == WLAN_EID_WPA) { + if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) { priv->sec_info.wpa_enabled = true; } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { priv->sec_info.wpa2_enabled = true; @@ -1253,7 +1253,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, } pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; /* Test to see if it is a WPA IE, if not, then it is a gen IE */ - if (((pvendor_ie->element_id == WLAN_EID_WPA) && + if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) || (pvendor_ie->element_id == WLAN_EID_RSN)) { diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h index 4dadf9880a97..5a8fec26136e 100644 --- a/drivers/net/wireless/orinoco/main.h +++ b/drivers/net/wireless/orinoco/main.h @@ -39,7 +39,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) { u8 *p = data; while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == WLAN_EID_GENERIC) && + if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) && (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) return p; p += p[1] + 2; From c46597f1dea200dfd0b7ace5d1efe816fb41c6ee Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 12 Oct 2012 12:28:15 +0200 Subject: [PATCH 27/38] wireless: gelic: make use of WLAN_EID_VENDOR_SPECIFIC The include file linux/ieee80211.h contains three definitions for the same thing in enum ieee80211_eid due to historic changes: /* Information Element IDs */ enum ieee80211_eid { : WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, : }; The standard refers to this as "vendor specific" element so the other two definitions are better not used. This patch changes the wireless drivers to use one definition, ie. WLAN_EID_VENDOR_SPECIFIC. Cc: David S. Miller Signed-off-by: Arend van Spriel Signed-off-by: Johannes Berg --- drivers/net/ethernet/toshiba/ps3_gelic_wireless.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index 961c8321451f..72b775fd49c8 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -452,7 +452,7 @@ static size_t gelic_wl_synthesize_ie(u8 *buf, if (rsn) *buf++ = WLAN_EID_RSN; else - *buf++ = WLAN_EID_GENERIC; + *buf++ = WLAN_EID_VENDOR_SPECIFIC; /* length filed; set later */ buf++; @@ -540,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, break; switch (item_id) { - case WLAN_EID_GENERIC: + case WLAN_EID_VENDOR_SPECIFIC: if ((OUI_LEN + 1 <= item_len) && !memcmp(pos, wpa_oui, OUI_LEN) && pos[OUI_LEN] == 0x01) { From 3821b4247b40d6b95a59a2895ea6e9bd3f983f04 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 12 Oct 2012 12:28:16 +0200 Subject: [PATCH 28/38] wireless: remove duplicate enum ieee80211_eid definitions WLAN_EID_WPA and WLAN_EID_GENERIC mapped to the same value as WLAN_EID_VENDOR_SPECIFIC. The last one being more in line with the standard specification. Removing WLAN_EID_WPA and WLAN_EID_GENERIC as there are no longer drivers using these. Cc: Johannes Berg Signed-off-by: Arend van Spriel Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 8c803f0e4925..85764a900731 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1457,8 +1457,6 @@ enum ieee80211_eid { WLAN_EID_RSN = 48, WLAN_EID_MMIE = 76, - WLAN_EID_WPA = 221, - WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, WLAN_EID_QOS_PARAMETER = 222, From 8ba7acf376e39ff2b987bc8fb71eb599023af314 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 30 Sep 2012 17:07:19 +0200 Subject: [PATCH 29/38] mac80211: remove unimplemented mesh vendor sync There's no vendor-specific mesh sync implemented and there don't need to be dummy handlers that only print messages, so remove that code. While at it, also constify the mesh sync ops. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_sync.c | 55 +++----------------------------------- 3 files changed, 5 insertions(+), 54 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 02e47930964f..ebc1b5dc4127 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -610,7 +610,7 @@ struct ieee80211_if_mesh { IEEE80211_MESH_SEC_SECURED = 0x2, } security; /* Extensible Synchronization Framework */ - struct ieee80211_mesh_sync_ops *sync_ops; + const struct ieee80211_mesh_sync_ops *sync_ops; s64 sync_offset_clockdrift_max; spinlock_t sync_offset_lock; bool adjusting_tbtt; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 8334e9445195..9285f3f67e66 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -256,7 +256,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); -struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); +const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); /* Mesh paths */ int mesh_nexthop_lookup(struct sk_buff *skb, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index a16b7b4b1e02..407c8705e10d 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -234,49 +234,7 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) spin_unlock_bh(&ifmsh->sync_offset_lock); } -static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - u8 offset; - - if (!ifmsh->ie || !ifmsh->ie_len) - return NULL; - - offset = ieee80211_ie_split_vendor(ifmsh->ie, - ifmsh->ie_len, 0); - - if (!offset) - return NULL; - - return ifmsh->ie + offset + 2; -} - -static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, - u16 stype, - struct ieee80211_mgmt *mgmt, - struct ieee802_11_elems *elems, - struct ieee80211_rx_status *rx_status) -{ - const u8 *oui; - - WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n"); - oui = mesh_get_vendor_oui(sdata); - /* here you would implement the vendor offset tracking for this oui */ -} - -static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) -{ - const u8 *oui; - - WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n"); - oui = mesh_get_vendor_oui(sdata); - /* here you would implement the vendor tsf adjustment for this oui */ -} - -/* global variable */ -static struct sync_method sync_methods[] = { +static const struct sync_method sync_methods[] = { { .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, .ops = { @@ -284,18 +242,11 @@ static struct sync_method sync_methods[] = { .adjust_tbtt = &mesh_sync_offset_adjust_tbtt, } }, - { - .method = IEEE80211_SYNC_METHOD_VENDOR, - .ops = { - .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp, - .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt, - } - }, }; -struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) +const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) { - struct ieee80211_mesh_sync_ops *ops = NULL; + const struct ieee80211_mesh_sync_ops *ops = NULL; u8 i; for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { From 444e38035eafba2993a690497b205ce385df3a8e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 30 Sep 2012 17:08:35 +0200 Subject: [PATCH 30/38] mac80211: remove some unused code There are a number of unused variables that gcc pointed out (when building with W=1) as well as some conditions that can never be true due to the datatypes used: unsigned values can't be less than zero. Remove this code. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 -- net/mac80211/mlme.c | 7 +------ net/mac80211/rx.c | 11 +++-------- net/mac80211/tx.c | 2 -- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ed27988f9d35..5739bfbf2999 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2823,7 +2823,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - struct ieee80211_tx_info *info; struct sk_buff *skb = NULL; bool send_direct; int ret; @@ -2849,7 +2848,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, if (!skb) return -ENOMEM; - info = IEEE80211_SKB_CB(skb); skb_reserve(skb, local->hw.extra_tx_headroom); switch (action_code) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ab39c4f44e5c..469d86419bc6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2617,14 +2617,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && - !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[chan->band]; - + !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, bssid, true); - } if (elems.country_elem && elems.pwr_constr_elem && mgmt->u.probe_resp.capab_info & diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 61c621e9273f..9f64fc4ecd29 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1384,9 +1384,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, struct sk_buff **skb) { struct ieee80211_fragment_entry *entry; - int idx; - idx = sdata->fragment_next; entry = &sdata->fragments[sdata->fragment_next++]; if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) sdata->fragment_next = 0; @@ -3010,8 +3008,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) WARN_ON_ONCE(softirq_count() == 0); - if (WARN_ON(status->band < 0 || - status->band >= IEEE80211_NUM_BANDS)) + if (WARN_ON(status->band >= IEEE80211_NUM_BANDS)) goto drop; sband = local->hw.wiphy->bands[status->band]; @@ -3056,8 +3053,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) * hardware error. The driver should catch hardware * errors. */ - if (WARN((status->rate_idx < 0 || - status->rate_idx > 76), + if (WARN(status->rate_idx > 76, "Rate marked as an HT rate but passed " "status->rate_idx is not " "an MCS index [0-76]: %d (0x%02x)\n", @@ -3065,8 +3061,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) status->rate_idx)) goto drop; } else { - if (WARN_ON(status->rate_idx < 0 || - status->rate_idx >= sband->n_bitrates)) + if (WARN_ON(status->rate_idx >= sband->n_bitrates)) goto drop; rate = &sband->bitrates[status->rate_idx]; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index eee448ac71ff..bbe1d86beea1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -944,7 +944,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) fragnum = 0; skb_queue_walk(&tx->skbs, skb) { - int next_len; const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); hdr = (void *)skb->data; @@ -963,7 +962,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { hdr->frame_control &= ~morefrags; - next_len = 0; } hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); fragnum++; From 8c1dddd6070a900918561f162621ef4957ff36c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 30 Sep 2012 17:12:45 +0200 Subject: [PATCH 31/38] mac80211: use __printf attribute in debugfs The internal function mac80211_format_buffer() has a printf-style argument list, so add the attribute to have gcc verify that list. Signed-off-by: Johannes Berg --- net/mac80211/debugfs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 9be4e6d71d00..214ed4ecd739 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -2,9 +2,9 @@ #define __MAC80211_DEBUGFS_H #ifdef CONFIG_MAC80211_DEBUGFS -extern void debugfs_hw_add(struct ieee80211_local *local); -extern int mac80211_format_buffer(char __user *userbuf, size_t count, - loff_t *ppos, char *fmt, ...); +void debugfs_hw_add(struct ieee80211_local *local); +int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count, + loff_t *ppos, char *fmt, ...); #else static inline void debugfs_hw_add(struct ieee80211_local *local) { From f53c6a0d74dffd6e82defe195bd5b97c7d384341 Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Wed, 17 Oct 2012 20:21:30 -0700 Subject: [PATCH 32/38] mac80211: fix copy-paste typo in Kconfig Signed-off-by: Marco Porsch Signed-off-by: Johannes Berg --- net/mac80211/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 63af25458fda..b4ecf267a34b 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -248,7 +248,7 @@ config MAC80211_MHWMP_DEBUG Do not select this option. config MAC80211_MESH_SYNC_DEBUG - bool "Verbose mesh mesh synchronization debugging" + bool "Verbose mesh synchronization debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH ---help--- From de7044ee85a9ba9e8529b0250f2882724407c977 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 18 Oct 2012 10:19:28 +0530 Subject: [PATCH 33/38] cfg80211: Disallow HT/WEP in IBSS mode Currently, a user is allowed to choose a HT operating channel with WEP when creating an IBSS network. WEP is not allowed in HT configuration - this patch ensures that such requests are denied. Signed-off-by: Sujith Manoharan Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9e5a7206b0b4..48d754c9adb8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -692,7 +692,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) static struct cfg80211_cached_keys * nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, - struct nlattr *keys) + struct nlattr *keys, bool *no_ht) { struct key_parse parse; struct nlattr *key; @@ -735,6 +735,12 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, result->params[parse.idx].key_len = parse.p.key_len; result->params[parse.idx].key = result->data[parse.idx]; memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); + + if (parse.p.cipher == WLAN_CIPHER_SUITE_WEP40 || + parse.p.cipher == WLAN_CIPHER_SUITE_WEP104) { + if (no_ht) + *no_ht = true; + } } return result; @@ -5406,10 +5412,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { + bool no_ht = false; + connkeys = nl80211_parse_connkeys(rdev, - info->attrs[NL80211_ATTR_KEYS]); + info->attrs[NL80211_ATTR_KEYS], + &no_ht); if (IS_ERR(connkeys)) return PTR_ERR(connkeys); + + if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) { + kfree(connkeys); + return -EINVAL; + } } ibss.control_port = @@ -5710,7 +5724,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { connkeys = nl80211_parse_connkeys(rdev, - info->attrs[NL80211_ATTR_KEYS]); + info->attrs[NL80211_ATTR_KEYS], NULL); if (IS_ERR(connkeys)) return PTR_ERR(connkeys); } From e35e4d28b687d4e849573419fdcf90f1cce2a14c Mon Sep 17 00:00:00 2001 From: Hila Gonen Date: Wed, 27 Jun 2012 17:19:42 +0300 Subject: [PATCH 34/38] cfg80211: add wrappers for registered_device_ops This will allow adding central tracing like in mac80211. Signed-off-by: Hila Gonen Reviewed-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/wireless/ap.c | 3 +- net/wireless/chan.c | 3 +- net/wireless/core.c | 10 +- net/wireless/ethtool.c | 15 +- net/wireless/ibss.c | 7 +- net/wireless/mesh.c | 10 +- net/wireless/mlme.c | 26 +- net/wireless/nl80211.c | 135 +++++---- net/wireless/rdev-ops.h | 558 +++++++++++++++++++++++++++++++++++++ net/wireless/scan.c | 5 +- net/wireless/sme.c | 9 +- net/wireless/sysfs.c | 5 +- net/wireless/util.c | 14 +- net/wireless/wext-compat.c | 48 ++-- 14 files changed, 700 insertions(+), 148 deletions(-) create mode 100644 net/wireless/rdev-ops.h diff --git a/net/wireless/ap.c b/net/wireless/ap.c index fcc60d8dbefa..e143505f05bc 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -3,6 +3,7 @@ #include #include "nl80211.h" #include "core.h" +#include "rdev-ops.h" static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, @@ -23,7 +24,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, if (!wdev->beacon_interval) return -ENOENT; - err = rdev->ops->stop_ap(&rdev->wiphy, dev); + err = rdev_stop_ap(rdev, dev); if (!err) { wdev->beacon_interval = 0; wdev->channel = NULL; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2f876b9ee344..71c362587965 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -9,6 +9,7 @@ #include #include #include "core.h" +#include "rdev-ops.h" struct ieee80211_channel * rdev_freq_to_chan(struct cfg80211_registered_device *rdev, @@ -92,7 +93,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, if (!chan) return -EINVAL; - return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); + return rdev_set_monitor_channel(rdev, chan, chantype); } void diff --git a/net/wireless/core.c b/net/wireless/core.c index 48c2ea4712e9..f280f48fbd43 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -26,6 +26,7 @@ #include "debugfs.h" #include "wext-compat.h" #include "ethtool.h" +#include "rdev-ops.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -216,7 +217,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) { struct cfg80211_registered_device *rdev = data; - rdev->ops->rfkill_poll(&rdev->wiphy); + rdev_rfkill_poll(rdev); } static int cfg80211_rfkill_set_block(void *data, bool blocked) @@ -690,7 +691,7 @@ void wiphy_unregister(struct wiphy *wiphy) flush_work(&rdev->event_work); if (rdev->wowlan && rdev->ops->set_wakeup) - rdev->ops->set_wakeup(&rdev->wiphy, false); + rdev_set_wakeup(rdev, false); cfg80211_rdev_free_wowlan(rdev); } EXPORT_SYMBOL(wiphy_unregister); @@ -964,9 +965,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, if ((wdev->iftype == NL80211_IFTYPE_STATION || wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && rdev->ops->set_power_mgmt) - if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, - wdev->ps, - wdev->ps_timeout)) { + if (rdev_set_power_mgmt(rdev, dev, wdev->ps, + wdev->ps_timeout)) { /* assume this means it's off */ wdev->ps = false; } diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index 7eecdf40cf80..48c48ffafa1d 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -2,6 +2,7 @@ #include #include "core.h" #include "ethtool.h" +#include "rdev-ops.h" static void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -47,9 +48,8 @@ static void cfg80211_get_ringparam(struct net_device *dev, memset(rp, 0, sizeof(*rp)); if (rdev->ops->get_ringparam) - rdev->ops->get_ringparam(wdev->wiphy, - &rp->tx_pending, &rp->tx_max_pending, - &rp->rx_pending, &rp->rx_max_pending); + rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending, + &rp->rx_pending, &rp->rx_max_pending); } static int cfg80211_set_ringparam(struct net_device *dev, @@ -62,8 +62,7 @@ static int cfg80211_set_ringparam(struct net_device *dev, return -EINVAL; if (rdev->ops->set_ringparam) - return rdev->ops->set_ringparam(wdev->wiphy, - rp->tx_pending, rp->rx_pending); + return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending); return -ENOTSUPP; } @@ -73,7 +72,7 @@ static int cfg80211_get_sset_count(struct net_device *dev, int sset) struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); if (rdev->ops->get_et_sset_count) - return rdev->ops->get_et_sset_count(wdev->wiphy, dev, sset); + return rdev_get_et_sset_count(rdev, dev, sset); return -EOPNOTSUPP; } @@ -83,7 +82,7 @@ static void cfg80211_get_stats(struct net_device *dev, struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); if (rdev->ops->get_et_stats) - rdev->ops->get_et_stats(wdev->wiphy, dev, stats, data); + rdev_get_et_stats(rdev, dev, stats, data); } static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) @@ -91,7 +90,7 @@ static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); if (rdev->ops->get_et_strings) - rdev->ops->get_et_strings(wdev->wiphy, dev, sset, data); + rdev_get_et_strings(rdev, dev, sset, data); } const struct ethtool_ops cfg80211_ethtool_ops = { diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index ca5672f6ee2f..7fda94fb1a3e 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -11,6 +11,7 @@ #include #include "wext-compat.h" #include "nl80211.h" +#include "rdev-ops.h" void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) @@ -128,7 +129,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return err; } - err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); + err = rdev_join_ibss(rdev, dev, params); if (err) { wdev->connect_keys = NULL; wdev->sme_state = CFG80211_SME_IDLE; @@ -175,7 +176,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); + rdev_del_key(rdev, dev, i, false, NULL); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); @@ -211,7 +212,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (!wdev->ssid_len) return -ENOLINK; - err = rdev->ops->leave_ibss(&rdev->wiphy, dev); + err = rdev_leave_ibss(rdev, dev); if (err) return err; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index c384e77ff77a..a18bb3417be5 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -3,6 +3,7 @@ #include #include "nl80211.h" #include "core.h" +#include "rdev-ops.h" /* Default values, timeouts in ms */ #define MESH_TTL 31 @@ -160,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (err) return err; - err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); + err = rdev_join_mesh(rdev, dev, conf, setup); if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; @@ -220,9 +221,8 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, if (err) return err; - err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, - wdev->netdev, - channel); + err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, + channel); if (!err) wdev->channel = channel; @@ -267,7 +267,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, if (!wdev->mesh_id_len) return -ENOTCONN; - err = rdev->ops->leave_mesh(&rdev->wiphy, dev); + err = rdev_leave_mesh(rdev, dev); if (!err) { wdev->mesh_id_len = 0; wdev->channel = NULL; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 460d49325741..2a74395e6ab3 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -15,6 +15,8 @@ #include #include "core.h" #include "nl80211.h" +#include "rdev-ops.h" + void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) { @@ -310,7 +312,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (err) goto out; - err = rdev->ops->auth(&rdev->wiphy, dev, &req); + err = rdev_auth(rdev, dev, &req); out: cfg80211_put_bss(req.bss); @@ -415,7 +417,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, if (err) goto out; - err = rdev->ops->assoc(&rdev->wiphy, dev, &req); + err = rdev_assoc(rdev, dev, &req); out: if (err) { @@ -477,7 +479,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, return 0; } - return rdev->ops->deauth(&rdev->wiphy, dev, &req); + return rdev_deauth(rdev, dev, &req); } int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, @@ -522,7 +524,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, else return -ENOTCONN; - return rdev->ops->disassoc(&rdev->wiphy, dev, &req); + return rdev_disassoc(rdev, dev, &req); } int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, @@ -563,7 +565,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); req.bssid = bssid; - rdev->ops->deauth(&rdev->wiphy, dev, &req); + rdev_deauth(rdev, dev, &req); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); @@ -693,7 +695,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, list_add(&nreg->list, &wdev->mgmt_registrations); if (rdev->ops->mgmt_frame_register) - rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true); + rdev_mgmt_frame_register(rdev, wdev, frame_type, true); out: spin_unlock_bh(&wdev->mgmt_registrations_lock); @@ -716,8 +718,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) if (rdev->ops->mgmt_frame_register) { u16 frame_type = le16_to_cpu(reg->frame_type); - rdev->ops->mgmt_frame_register(wiphy, wdev, - frame_type, false); + rdev_mgmt_frame_register(rdev, wdev, + frame_type, false); } list_del(®->list); @@ -843,10 +845,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return -EINVAL; /* Transmit the Action frame as requested by user space */ - return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, - channel_type, channel_type_valid, - wait, buf, len, no_cck, dont_wait_for_ack, - cookie); + return rdev_mgmt_tx(rdev, wdev, chan, offchan, + channel_type, channel_type_valid, + wait, buf, len, no_cck, dont_wait_for_ack, + cookie); } bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48d754c9adb8..e26f7455538d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -22,6 +22,7 @@ #include "core.h" #include "nl80211.h" #include "reg.h" +#include "rdev-ops.h" static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct genl_info *info, @@ -951,7 +952,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { u32 tx_ant = 0, rx_ant = 0; int res; - res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); + res = rdev_get_antenna(dev, &tx_ant, &rx_ant); if (!res) { if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant) || @@ -1465,7 +1466,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); + return rdev_set_wds_peer(rdev, dev, bssid); } @@ -1570,9 +1571,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (result) goto bad_res; - result = rdev->ops->set_txq_params(&rdev->wiphy, - netdev, - &txq_params); + result = rdev_set_txq_params(rdev, netdev, + &txq_params); if (result) goto bad_res; } @@ -1607,7 +1607,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) mbm = nla_get_u32(info->attrs[idx]); } - result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); + result = rdev_set_tx_power(rdev, type, mbm); if (result) goto bad_res; } @@ -1636,7 +1636,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; - result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); + result = rdev_set_antenna(rdev, tx_ant, rx_ant); if (result) goto bad_res; } @@ -1721,7 +1721,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (changed & WIPHY_PARAM_COVERAGE_CLASS) rdev->wiphy.coverage_class = coverage_class; - result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + result = rdev_set_wiphy_params(rdev, changed); if (result) { rdev->wiphy.retry_short = old_retry_short; rdev->wiphy.retry_long = old_retry_long; @@ -1773,8 +1773,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag struct ieee80211_channel *chan; enum nl80211_channel_type channel_type; - chan = rdev->ops->get_channel(&rdev->wiphy, wdev, - &channel_type); + chan = rdev_get_channel(rdev, wdev, &channel_type); if (chan && (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || @@ -2022,9 +2021,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); - wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, - nla_data(info->attrs[NL80211_ATTR_IFNAME]), - type, err ? NULL : &flags, ¶ms); + wdev = rdev_add_virtual_intf(rdev, + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags, ¶ms); if (IS_ERR(wdev)) { nlmsg_free(msg); return PTR_ERR(wdev); @@ -2091,7 +2090,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) if (!wdev->netdev) info->user_ptr[1] = NULL; - return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); + return rdev_del_virtual_intf(rdev, wdev); } static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) @@ -2108,7 +2107,7 @@ static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]); - return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map); + return rdev_set_noack_map(rdev, dev, noack_map); } struct get_key_cookie { @@ -2218,8 +2217,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) return -ENOENT; - err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, - mac_addr, &cookie, get_key_callback); + err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie, + get_key_callback); if (err) goto free_msg; @@ -2267,7 +2266,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, + err = rdev_set_default_key(rdev, dev, key.idx, key.def_uni, key.def_multi); if (err) @@ -2291,8 +2290,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, - dev, key.idx); + err = rdev_set_default_mgmt_key(rdev, dev, key.idx); if (err) goto out; @@ -2348,9 +2346,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); if (!err) - err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, - key.type == NL80211_KEYTYPE_PAIRWISE, - mac_addr, &key.p); + err = rdev_add_key(rdev, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr, &key.p); wdev_unlock(dev->ieee80211_ptr); return err; @@ -2394,9 +2392,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) err = -ENOENT; if (!err) - err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, - key.type == NL80211_KEYTYPE_PAIRWISE, - mac_addr); + err = rdev_del_key(rdev, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr); #ifdef CONFIG_CFG80211_WEXT if (!err) { @@ -2640,7 +2638,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (err) return err; - err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); + err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { wdev->preset_chan = params.channel; wdev->preset_chantype = params.channel_type; @@ -2672,7 +2670,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (err) return err; - return rdev->ops->change_beacon(&rdev->wiphy, dev, ¶ms); + return rdev_change_beacon(rdev, dev, ¶ms); } static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) @@ -2956,8 +2954,8 @@ static int nl80211_dump_station(struct sk_buff *skb, while (1) { memset(&sinfo, 0, sizeof(sinfo)); - err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, - mac_addr, &sinfo); + err = rdev_dump_station(dev, netdev, sta_idx, + mac_addr, &sinfo); if (err == -ENOENT) break; if (err) @@ -3002,7 +3000,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->get_station) return -EOPNOTSUPP; - err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); + err = rdev_get_station(rdev, dev, mac_addr, &sinfo); if (err) return err; @@ -3179,7 +3177,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) /* be aware of params.vlan when changing code here */ - err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); + err = rdev_change_station(rdev, dev, mac_addr, ¶ms); if (params.vlan) dev_put(params.vlan); @@ -3312,7 +3310,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) /* be aware of params.vlan when changing code here */ - err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); + err = rdev_add_station(rdev, dev, mac_addr, ¶ms); if (params.vlan) dev_put(params.vlan); @@ -3337,7 +3335,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_station) return -EOPNOTSUPP; - return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); + return rdev_del_station(rdev, dev, mac_addr); } static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, @@ -3419,8 +3417,8 @@ static int nl80211_dump_mpath(struct sk_buff *skb, } while (1) { - err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, - dst, next_hop, &pinfo); + err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop, + &pinfo); if (err == -ENOENT) break; if (err) @@ -3467,7 +3465,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); + err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo); if (err) return err; @@ -3506,7 +3504,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); + return rdev_change_mpath(rdev, dev, dst, next_hop); } static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) @@ -3531,7 +3529,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); + return rdev_add_mpath(rdev, dev, dst, next_hop); } static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) @@ -3546,7 +3544,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_mpath) return -EOPNOTSUPP; - return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); + return rdev_del_mpath(rdev, dev, dst); } static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) @@ -3591,7 +3589,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); + return rdev_change_bss(rdev, dev, ¶ms); } static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { @@ -3705,8 +3703,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, if (!wdev->mesh_id_len) memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); else - err = rdev->ops->get_mesh_config(&rdev->wiphy, dev, - &cur_params); + err = rdev_get_mesh_config(rdev, dev, &cur_params); wdev_unlock(wdev); if (err) @@ -4008,8 +4005,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, err = -ENOLINK; if (!err) - err = rdev->ops->update_mesh_config(&rdev->wiphy, dev, - mask, &cfg); + err = rdev_update_mesh_config(rdev, dev, mask, &cfg); wdev_unlock(wdev); @@ -4394,7 +4390,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->scan_start = jiffies; rdev->scan_req = request; - err = rdev->ops->scan(&rdev->wiphy, request); + err = rdev_scan(rdev, request); if (!err) { nl80211_send_scan_start(rdev, wdev); @@ -4635,7 +4631,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->interval = interval; request->scan_start = jiffies; - err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); + err = rdev_sched_scan_start(rdev, dev, request); if (!err) { rdev->sched_scan_req = request; nl80211_send_sched_scan(rdev, dev, @@ -4878,8 +4874,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, while (1) { struct ieee80211_channel *chan; - res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, - &survey); + res = rdev_dump_survey(dev, netdev, survey_idx, &survey); if (res == -ENOENT) break; if (res) @@ -5465,7 +5460,7 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) err = -EOPNOTSUPP; if (rdev->ops->testmode_cmd) { rdev->testmode_info = info; - err = rdev->ops->testmode_cmd(&rdev->wiphy, + err = rdev_testmode_cmd(rdev, nla_data(info->attrs[NL80211_ATTR_TESTDATA]), nla_len(info->attrs[NL80211_ATTR_TESTDATA])); rdev->testmode_info = NULL; @@ -5547,8 +5542,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb, genlmsg_cancel(skb, hdr); break; } - err = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, - data, data_len); + err = rdev_testmode_dump(rdev, skb, cb, data, data_len); nla_nest_end(skb, tmdata); if (err == -ENOBUFS || err == -ENOENT) { @@ -5853,7 +5847,7 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->flush_pmksa) return -EOPNOTSUPP; - return rdev->ops->flush_pmksa(&rdev->wiphy, dev); + return rdev_flush_pmksa(rdev, dev); } static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) @@ -5880,10 +5874,10 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); - return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, - nla_data(info->attrs[NL80211_ATTR_IE]), - nla_len(info->attrs[NL80211_ATTR_IE])); + return rdev_tdls_mgmt(rdev, dev, peer, action_code, + dialog_token, status_code, + nla_data(info->attrs[NL80211_ATTR_IE]), + nla_len(info->attrs[NL80211_ATTR_IE])); } static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) @@ -5904,7 +5898,7 @@ static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]); peer = nla_data(info->attrs[NL80211_ATTR_MAC]); - return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation); + return rdev_tdls_oper(rdev, dev, peer, operation); } static int nl80211_remain_on_channel(struct sk_buff *skb, @@ -5959,8 +5953,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, goto free_msg; } - err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, - channel_type, duration, &cookie); + err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration, + &cookie); if (err) goto free_msg; @@ -5994,7 +5988,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); + return rdev_cancel_remain_on_channel(rdev, wdev, cookie); } static u32 rateset_to_mask(struct ieee80211_supported_band *sband, @@ -6137,7 +6131,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, } } - return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); + return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); } static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) @@ -6312,7 +6306,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); + return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie); } static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) @@ -6342,8 +6336,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) if (state == wdev->ps) return 0; - err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, - wdev->ps_timeout); + err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout); if (!err) wdev->ps = state; return err; @@ -6423,8 +6416,7 @@ static int nl80211_set_cqm_txe(struct genl_info *info, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, - rate, pkts, intvl); + return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl); } static int nl80211_set_cqm_rssi(struct genl_info *info, @@ -6446,8 +6438,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, - threshold, hysteresis); + return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis); } static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) @@ -6772,7 +6763,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) set_wakeup: if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) - rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); + rdev_set_wakeup(rdev, rdev->wowlan); return 0; error: @@ -6828,7 +6819,7 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) goto out; } - err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data); + err = rdev_set_rekey_data(rdev, dev, &rekey_data); out: wdev_unlock(wdev); return err; @@ -6887,7 +6878,7 @@ static int nl80211_probe_client(struct sk_buff *skb, addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie); + err = rdev_probe_client(rdev, dev, addr, &cookie); if (err) goto free_msg; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h new file mode 100644 index 000000000000..b6fad29d656b --- /dev/null +++ b/net/wireless/rdev-ops.h @@ -0,0 +1,558 @@ +#ifndef __CFG80211_RDEV_OPS +#define __CFG80211_RDEV_OPS + +#include +#include +#include "core.h" + +static inline int rdev_suspend(struct cfg80211_registered_device *rdev) +{ + return rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); +} + +static inline int rdev_resume(struct cfg80211_registered_device *rdev) +{ + return rdev->ops->resume(&rdev->wiphy); +} + +static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev, + bool enabled) +{ + rdev->ops->set_wakeup(&rdev->wiphy, enabled); +} + +static inline struct wireless_dev +*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + return rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags, + params); +} + +static inline int +rdev_del_virtual_intf(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); +} + +static inline int +rdev_change_virtual_intf(struct cfg80211_registered_device *rdev, + struct net_device *dev, enum nl80211_iftype type, + u32 *flags, struct vif_params *params) +{ + return rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags, + params); +} + +static inline int rdev_add_key(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + return rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, + mac_addr, params); +} + +static inline int +rdev_get_key(struct cfg80211_registered_device *rdev, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params*)) +{ + return rdev->ops->get_key(&rdev->wiphy, netdev, key_index, pairwise, + mac_addr, cookie, callback); +} + +static inline int rdev_del_key(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + return rdev->ops->del_key(&rdev->wiphy, netdev, key_index, pairwise, + mac_addr); +} + +static inline int +rdev_set_default_key(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u8 key_index, bool unicast, + bool multicast) +{ + return rdev->ops->set_default_key(&rdev->wiphy, netdev, key_index, + unicast, multicast); +} + +static inline int +rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u8 key_index) +{ + return rdev->ops->set_default_mgmt_key(&rdev->wiphy, netdev, + key_index); +} + +static inline int rdev_start_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + return rdev->ops->start_ap(&rdev->wiphy, dev, settings); +} + +static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + return rdev->ops->change_beacon(&rdev->wiphy, dev, info); +} + +static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + return rdev->ops->stop_ap(&rdev->wiphy, dev); +} + +static inline int rdev_add_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *mac, + struct station_parameters *params) +{ + return rdev->ops->add_station(&rdev->wiphy, dev, mac, params); +} + +static inline int rdev_del_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *mac) +{ + return rdev->ops->del_station(&rdev->wiphy, dev, mac); +} + +static inline int rdev_change_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *mac, + struct station_parameters *params) +{ + return rdev->ops->change_station(&rdev->wiphy, dev, mac, params); +} + +static inline int rdev_get_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *mac, + struct station_info *sinfo) +{ + return rdev->ops->get_station(&rdev->wiphy, dev, mac, sinfo); +} + +static inline int rdev_dump_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, int idx, u8 *mac, + struct station_info *sinfo) +{ + return rdev->ops->dump_station(&rdev->wiphy, dev, idx, mac, sinfo); +} + +static inline int rdev_add_mpath(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *dst, u8 *next_hop) +{ + return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); +} + +static inline int rdev_del_mpath(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *dst) +{ + return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); +} + +static inline int rdev_change_mpath(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *dst, + u8 *next_hop) +{ + return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); +} + +static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *dst, u8 *next_hop, + struct mpath_info *pinfo) +{ + return rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, pinfo); +} + +static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, + struct net_device *dev, int idx, u8 *dst, + u8 *next_hop, struct mpath_info *pinfo) + +{ + return rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, + pinfo); +} + +static inline int +rdev_get_mesh_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct mesh_config *conf) +{ + return rdev->ops->get_mesh_config(&rdev->wiphy, dev, conf); +} + +static inline int +rdev_update_mesh_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, u32 mask, + const struct mesh_config *nconf) +{ + return rdev->ops->update_mesh_config(&rdev->wiphy, dev, mask, nconf); +} + +static inline int rdev_join_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev, + const struct mesh_config *conf, + const struct mesh_setup *setup) +{ + return rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); +} + + +static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + return rdev->ops->leave_mesh(&rdev->wiphy, dev); +} + +static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct bss_parameters *params) + +{ + return rdev->ops->change_bss(&rdev->wiphy, dev, params); +} + +static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_txq_params *params) + +{ + return rdev->ops->set_txq_params(&rdev->wiphy, dev, params); +} + +static inline int +rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan) +{ + return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, dev, chan); +} + +static inline int +rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, + channel_type); +} + +static inline int rdev_scan(struct cfg80211_registered_device *rdev, + struct cfg80211_scan_request *request) +{ + return rdev->ops->scan(&rdev->wiphy, request); +} + +static inline int rdev_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_auth_request *req) +{ + return rdev->ops->auth(&rdev->wiphy, dev, req); +} + +static inline int rdev_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_assoc_request *req) +{ + return rdev->ops->assoc(&rdev->wiphy, dev, req); +} + +static inline int rdev_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_deauth_request *req) +{ + return rdev->ops->deauth(&rdev->wiphy, dev, req); +} + +static inline int rdev_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_disassoc_request *req) +{ + return rdev->ops->disassoc(&rdev->wiphy, dev, req); +} + +static inline int rdev_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + return rdev->ops->connect(&rdev->wiphy, dev, sme); +} + +static inline int rdev_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason_code) +{ + return rdev->ops->disconnect(&rdev->wiphy, dev, reason_code); +} + +static inline int rdev_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + return rdev->ops->join_ibss(&rdev->wiphy, dev, params); +} + +static inline int rdev_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + return rdev->ops->leave_ibss(&rdev->wiphy, dev); +} + +static inline int +rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) +{ + return rdev->ops->set_wiphy_params(&rdev->wiphy, changed); +} + +static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, + enum nl80211_tx_power_setting type, int mbm) +{ + return rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); +} + +static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, + int *dbm) +{ + return rdev->ops->get_tx_power(&rdev->wiphy, dbm); +} + +static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *addr) +{ + return rdev->ops->set_wds_peer(&rdev->wiphy, dev, addr); +} + +static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) +{ + rdev->ops->rfkill_poll(&rdev->wiphy); +} + + +#ifdef CONFIG_NL80211_TESTMODE +static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev, + void *data, int len) +{ + return rdev->ops->testmode_cmd(&rdev->wiphy, data, len); +} + +static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev, + struct sk_buff *skb, + struct netlink_callback *cb, void *data, + int len) +{ + return rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, data, + len); +} +#endif + +static inline int +rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); +} + +static inline int rdev_dump_survey(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int idx, + struct survey_info *info) +{ + return rdev->ops->dump_survey(&rdev->wiphy, netdev, idx, info); +} + +static inline int rdev_set_pmksa(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + return rdev->ops->set_pmksa(&rdev->wiphy, netdev, pmksa); +} + +static inline int rdev_del_pmksa(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + return rdev->ops->del_pmksa(&rdev->wiphy, netdev, pmksa); +} + +static inline int rdev_flush_pmksa(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + return rdev->ops->flush_pmksa(&rdev->wiphy, netdev); +} + +static inline int +rdev_remain_on_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie) +{ + return rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, + channel_type, duration, cookie); +} + +static inline int +rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie) +{ + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); +} + +static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +{ + return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, + channel_type, channel_type_valid, wait, buf, + len, no_cck, dont_wait_for_ack, cookie); +} + +static inline int +rdev_mgmt_tx_cancel_wait(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie) +{ + return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); +} + +static inline int rdev_set_power_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool enabled, + int timeout) +{ + return rdev->ops->set_power_mgmt(&rdev->wiphy, dev, enabled, timeout); +} + +static inline int +rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, s32 rssi_thold, u32 rssi_hyst) +{ + return rdev->ops->set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold, + rssi_hyst); +} + +static inline int +rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, u32 rate, u32 pkts, u32 intvl) +{ + return rdev->ops->set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, + intvl); +} + +static inline void +rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u16 frame_type, bool reg) +{ + rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, + reg); +} + +static inline int rdev_set_antenna(struct cfg80211_registered_device *rdev, + u32 tx_ant, u32 rx_ant) +{ + return rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); +} + +static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev, + u32 *tx_ant, u32 *rx_ant) +{ + return rdev->ops->get_antenna(&rdev->wiphy, tx_ant, rx_ant); +} + +static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, + u32 tx, u32 rx) +{ + return rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); +} + +static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, + u32 *tx, u32 *tx_max, u32 *rx, + u32 *rx_max) +{ + rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); +} + +static inline int +rdev_sched_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + return rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); +} + +static inline int rdev_sched_scan_stop(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + return rdev->ops->sched_scan_stop(&rdev->wiphy, dev); +} + +static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + return rdev->ops->set_rekey_data(&rdev->wiphy, dev, data); +} + +static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *peer, + u8 action_code, u8 dialog_token, + u16 status_code, const u8 *buf, size_t len) +{ + return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); +} + +static inline int rdev_tdls_oper(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 *peer, + enum nl80211_tdls_operation oper) +{ + return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, oper); +} + +static inline int rdev_probe_client(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *peer, + u64 *cookie) +{ + return rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie); +} + +static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 noack_map) +{ + return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map); +} + +static inline int +rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, + struct net_device *dev, int sset) +{ + return rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); +} + +static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); +} + +static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, + struct net_device *dev, u32 sset, + u8 *data) +{ + rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); +} + +static inline struct ieee80211_channel +*rdev_get_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, enum nl80211_channel_type *type) +{ + return rdev->ops->get_channel(&rdev->wiphy, wdev, type); +} + +#endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a8d5a9a07e49..a957077dd961 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -17,6 +17,7 @@ #include "core.h" #include "nl80211.h" #include "wext-compat.h" +#include "rdev-ops.h" #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) @@ -211,7 +212,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, dev = rdev->sched_scan_req->dev; if (!driver_initiated) { - int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + int err = rdev_sched_scan_stop(rdev, dev); if (err) return err; } @@ -1052,7 +1053,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; rdev->scan_req = creq; - err = rdev->ops->scan(wiphy, creq); + err = rdev_scan(rdev, creq); if (err) { rdev->scan_req = NULL; /* creq will be freed below */ diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 07d717eb9e2a..c7490027237d 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -16,6 +16,7 @@ #include #include "nl80211.h" #include "reg.h" +#include "rdev-ops.h" struct cfg80211_conn { struct cfg80211_connect_params params; @@ -142,7 +143,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) rdev->scan_req = request; - err = rdev->ops->scan(wdev->wiphy, request); + err = rdev_scan(rdev, request); if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; nl80211_send_scan_start(rdev, wdev); @@ -717,7 +718,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); + rdev_del_key(rdev, dev, i, false, NULL); #ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); @@ -893,7 +894,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, } else { wdev->sme_state = CFG80211_SME_CONNECTING; wdev->connect_keys = connkeys; - err = rdev->ops->connect(&rdev->wiphy, dev, connect); + err = rdev_connect(rdev, dev, connect); if (err) { wdev->connect_keys = NULL; wdev->sme_state = CFG80211_SME_IDLE; @@ -965,7 +966,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, if (err) return err; } else { - err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); + err = rdev_disconnect(rdev, dev, reason); if (err) return err; } diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index ff574597a854..9bf6d5e32166 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -16,6 +16,7 @@ #include #include "sysfs.h" #include "core.h" +#include "rdev-ops.h" static inline struct cfg80211_registered_device *dev_to_rdev( struct device *dev) @@ -94,7 +95,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) if (rdev->ops->suspend) { rtnl_lock(); if (rdev->wiphy.registered) - ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); + ret = rdev_suspend(rdev); rtnl_unlock(); } @@ -114,7 +115,7 @@ static int wiphy_resume(struct device *dev) if (rdev->ops->resume) { rtnl_lock(); if (rdev->wiphy.registered) - ret = rdev->ops->resume(&rdev->wiphy); + ret = rdev_resume(rdev); rtnl_unlock(); } diff --git a/net/wireless/util.c b/net/wireless/util.c index ef35f4ef2aa6..343f13c1d31d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -11,6 +11,8 @@ #include #include #include "core.h" +#include "rdev-ops.h" + struct ieee80211_rate * ieee80211_get_response_rate(struct ieee80211_supported_band *sband, @@ -703,19 +705,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) for (i = 0; i < 6; i++) { if (!wdev->connect_keys->params[i].cipher) continue; - if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, - &wdev->connect_keys->params[i])) { + if (rdev_add_key(rdev, dev, i, false, NULL, + &wdev->connect_keys->params[i])) { netdev_err(dev, "failed to set key %d\n", i); continue; } if (wdev->connect_keys->def == i) - if (rdev->ops->set_default_key(wdev->wiphy, dev, - i, true, true)) { + if (rdev_set_default_key(rdev, dev, i, true, true)) { netdev_err(dev, "failed to set defkey %d\n", i); continue; } if (wdev->connect_keys->defmgmt == i) - if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) + if (rdev_set_default_mgmt_key(rdev, dev, i)) netdev_err(dev, "failed to set mgtdef %d\n", i); } @@ -848,8 +849,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, cfg80211_process_rdev_events(rdev); } - err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, - ntype, flags, params); + err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params); WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 494379eb464f..6488d2dbc1d7 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -19,6 +19,7 @@ #include #include "wext-compat.h" #include "core.h" +#include "rdev-ops.h" int cfg80211_wext_giwname(struct net_device *dev, struct iw_request_info *info, @@ -301,8 +302,7 @@ int cfg80211_wext_siwrts(struct net_device *dev, else wdev->wiphy->rts_threshold = rts->value; - err = rdev->ops->set_wiphy_params(wdev->wiphy, - WIPHY_PARAM_RTS_THRESHOLD); + err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_RTS_THRESHOLD); if (err) wdev->wiphy->rts_threshold = orts; @@ -342,8 +342,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev, wdev->wiphy->frag_threshold = frag->value & ~0x1; } - err = rdev->ops->set_wiphy_params(wdev->wiphy, - WIPHY_PARAM_FRAG_THRESHOLD); + err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_FRAG_THRESHOLD); if (err) wdev->wiphy->frag_threshold = ofrag; @@ -396,7 +395,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev, if (!changed) return 0; - err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); + err = rdev_set_wiphy_params(rdev, changed); if (err) { wdev->wiphy->retry_short = oshort; wdev->wiphy->retry_long = olong; @@ -490,8 +489,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) err = -ENOENT; else - err = rdev->ops->del_key(&rdev->wiphy, dev, idx, - pairwise, addr); + err = rdev_del_key(rdev, dev, idx, pairwise, + addr); } wdev->wext.connect.privacy = false; /* @@ -525,8 +524,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, err = 0; if (wdev->current_bss) - err = rdev->ops->add_key(&rdev->wiphy, dev, idx, - pairwise, addr, params); + err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); if (err) return err; @@ -552,8 +550,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, __cfg80211_leave_ibss(rdev, wdev->netdev, true); rejoin = true; } - err = rdev->ops->set_default_key(&rdev->wiphy, dev, - idx, true, true); + err = rdev_set_default_key(rdev, dev, idx, true, true); } if (!err) { wdev->wext.default_key = idx; @@ -566,8 +563,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { if (wdev->current_bss) - err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, - dev, idx); + err = rdev_set_default_mgmt_key(rdev, dev, idx); if (!err) wdev->wext.default_mgmt_key = idx; return err; @@ -631,8 +627,8 @@ static int cfg80211_wext_siwencode(struct net_device *dev, err = 0; wdev_lock(wdev); if (wdev->current_bss) - err = rdev->ops->set_default_key(&rdev->wiphy, dev, - idx, true, true); + err = rdev_set_default_key(rdev, dev, idx, true, + true); if (!err) wdev->wext.default_key = idx; wdev_unlock(wdev); @@ -839,7 +835,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, if (!rdev->ops->get_channel) return -EINVAL; - chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type); + chan = rdev_get_channel(rdev, wdev, &channel_type); if (!chan) return -EINVAL; freq->m = chan->center_freq; @@ -899,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev, return 0; } - return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); + return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm)); } static int cfg80211_wext_giwtxpower(struct net_device *dev, @@ -918,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, if (!rdev->ops->get_tx_power) return -EOPNOTSUPP; - err = rdev->ops->get_tx_power(wdev->wiphy, &val); + err = rdev_get_tx_power(rdev, &val); if (err) return err; @@ -1158,7 +1154,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev, timeout = wrq->value / 1000; } - err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); + err = rdev_set_power_mgmt(rdev, dev, ps, timeout); if (err) return err; @@ -1200,7 +1196,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev, if (!rdev->ops->set_wds_peer) return -EOPNOTSUPP; - err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); + err = rdev_set_wds_peer(rdev, dev, (u8 *)&addr->sa_data); if (err) return err; @@ -1272,7 +1268,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev, if (!match) return -EINVAL; - return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); + return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); } static int cfg80211_wext_giwrate(struct net_device *dev, @@ -1302,7 +1298,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, if (err) return err; - err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); + err = rdev_get_station(rdev, dev, addr, &sinfo); if (err) return err; @@ -1339,7 +1335,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); wdev_unlock(wdev); - if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) + if (rdev_get_station(rdev, dev, bssid, &sinfo)) return NULL; memset(&wstats, 0, sizeof(wstats)); @@ -1474,19 +1470,19 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev, if (!rdev->ops->set_pmksa) return -EOPNOTSUPP; - return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + return rdev_set_pmksa(rdev, dev, &cfg_pmksa); case IW_PMKSA_REMOVE: if (!rdev->ops->del_pmksa) return -EOPNOTSUPP; - return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + return rdev_del_pmksa(rdev, dev, &cfg_pmksa); case IW_PMKSA_FLUSH: if (!rdev->ops->flush_pmksa) return -EOPNOTSUPP; - return rdev->ops->flush_pmksa(&rdev->wiphy, dev); + return rdev_flush_pmksa(rdev, dev); default: return -EOPNOTSUPP; From 14e8a3c47e808772a5ba8118ef1f9a8d604dbbe5 Mon Sep 17 00:00:00 2001 From: Beni Lev Date: Tue, 31 Jul 2012 18:48:27 +0300 Subject: [PATCH 35/38] cfg80211: add tracing to rdev-ops Add tracing to make debugging cfg80211/mac80211 (or full-mac driver) interaction easier. Signed-off-by: Beni Lev Reviewed-by: Johannes Berg Reviewed-by: Hila Gonen Tested-by: Hila Gonen Reviewed-by: Emmanuel Grumbach [add a cast to int to sizeof() to avoid warning] Signed-off-by: Johannes Berg --- net/wireless/Makefile | 4 +- net/wireless/rdev-ops.h | 459 ++++++++-- net/wireless/trace.c | 7 + net/wireless/trace.h | 1750 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 2141 insertions(+), 79 deletions(-) create mode 100644 net/wireless/trace.c create mode 100644 net/wireless/trace.h diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 0f7e0d621ab0..a761670af31d 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -10,11 +10,13 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o obj-$(CONFIG_WEXT_PRIV) += wext-priv.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o -cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o +cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o +CFLAGS_trace.o := -I$(src) + ccflags-y += -D__CHECK_ENDIAN__ $(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index b6fad29d656b..4a88a39b1319 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -4,21 +4,32 @@ #include #include #include "core.h" +#include "trace.h" static inline int rdev_suspend(struct cfg80211_registered_device *rdev) { - return rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); + int ret; + trace_rdev_suspend(&rdev->wiphy, rdev->wowlan); + ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_resume(struct cfg80211_registered_device *rdev) { - return rdev->ops->resume(&rdev->wiphy); + int ret; + trace_rdev_resume(&rdev->wiphy); + ret = rdev->ops->resume(&rdev->wiphy); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev, bool enabled) { + trace_rdev_set_wakeup(&rdev->wiphy, enabled); rdev->ops->set_wakeup(&rdev->wiphy, enabled); + trace_rdev_return_void(&rdev->wiphy); } static inline struct wireless_dev @@ -26,15 +37,23 @@ static inline struct wireless_dev enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - return rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags, - params); + struct wireless_dev *ret; + trace_rdev_add_virtual_intf(&rdev->wiphy, name, type); + ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags, + params); + trace_rdev_return_wdev(&rdev->wiphy, ret); + return ret; } static inline int rdev_del_virtual_intf(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) { - return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); + int ret; + trace_rdev_del_virtual_intf(&rdev->wiphy, wdev); + ret = rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -42,8 +61,12 @@ rdev_change_virtual_intf(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - return rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags, - params); + int ret; + trace_rdev_change_virtual_intf(&rdev->wiphy, dev, type); + ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags, + params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_add_key(struct cfg80211_registered_device *rdev, @@ -51,8 +74,12 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev, bool pairwise, const u8 *mac_addr, struct key_params *params) { - return rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, + int ret; + trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr); + ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -60,16 +87,24 @@ rdev_get_key(struct cfg80211_registered_device *rdev, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params*)) { - return rdev->ops->get_key(&rdev->wiphy, netdev, key_index, pairwise, + int ret; + trace_rdev_get_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr); + ret = rdev->ops->get_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr, cookie, callback); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_del_key(struct cfg80211_registered_device *rdev, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { - return rdev->ops->del_key(&rdev->wiphy, netdev, key_index, pairwise, + int ret; + trace_rdev_del_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr); + ret = rdev->ops->del_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -77,96 +112,154 @@ rdev_set_default_key(struct cfg80211_registered_device *rdev, struct net_device *netdev, u8 key_index, bool unicast, bool multicast) { - return rdev->ops->set_default_key(&rdev->wiphy, netdev, key_index, + int ret; + trace_rdev_set_default_key(&rdev->wiphy, netdev, key_index, + unicast, multicast); + ret = rdev->ops->set_default_key(&rdev->wiphy, netdev, key_index, unicast, multicast); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev, struct net_device *netdev, u8 key_index) { - return rdev->ops->set_default_mgmt_key(&rdev->wiphy, netdev, + int ret; + trace_rdev_set_default_mgmt_key(&rdev->wiphy, netdev, key_index); + ret = rdev->ops->set_default_mgmt_key(&rdev->wiphy, netdev, key_index); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_start_ap(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_ap_settings *settings) { - return rdev->ops->start_ap(&rdev->wiphy, dev, settings); + int ret; + trace_rdev_start_ap(&rdev->wiphy, dev, settings); + ret = rdev->ops->start_ap(&rdev->wiphy, dev, settings); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_beacon_data *info) { - return rdev->ops->change_beacon(&rdev->wiphy, dev, info); + int ret; + trace_rdev_change_beacon(&rdev->wiphy, dev, info); + ret = rdev->ops->change_beacon(&rdev->wiphy, dev, info); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev, struct net_device *dev) { - return rdev->ops->stop_ap(&rdev->wiphy, dev); + int ret; + trace_rdev_stop_ap(&rdev->wiphy, dev); + ret = rdev->ops->stop_ap(&rdev->wiphy, dev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_add_station(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *mac, struct station_parameters *params) { - return rdev->ops->add_station(&rdev->wiphy, dev, mac, params); + int ret; + trace_rdev_add_station(&rdev->wiphy, dev, mac, params); + ret = rdev->ops->add_station(&rdev->wiphy, dev, mac, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_del_station(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *mac) { - return rdev->ops->del_station(&rdev->wiphy, dev, mac); + int ret; + trace_rdev_del_station(&rdev->wiphy, dev, mac); + ret = rdev->ops->del_station(&rdev->wiphy, dev, mac); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_change_station(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *mac, struct station_parameters *params) { - return rdev->ops->change_station(&rdev->wiphy, dev, mac, params); + int ret; + trace_rdev_change_station(&rdev->wiphy, dev, mac, params); + ret = rdev->ops->change_station(&rdev->wiphy, dev, mac, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_get_station(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *mac, struct station_info *sinfo) { - return rdev->ops->get_station(&rdev->wiphy, dev, mac, sinfo); + int ret; + trace_rdev_get_station(&rdev->wiphy, dev, mac); + ret = rdev->ops->get_station(&rdev->wiphy, dev, mac, sinfo); + trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo); + return ret; } static inline int rdev_dump_station(struct cfg80211_registered_device *rdev, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { - return rdev->ops->dump_station(&rdev->wiphy, dev, idx, mac, sinfo); + int ret; + trace_rdev_dump_station(&rdev->wiphy, dev, idx, mac); + ret = rdev->ops->dump_station(&rdev->wiphy, dev, idx, mac, sinfo); + trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo); + return ret; } static inline int rdev_add_mpath(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *dst, u8 *next_hop) { - return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); + int ret; + trace_rdev_add_mpath(&rdev->wiphy, dev, dst, next_hop); + ret = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_del_mpath(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *dst) { - return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); + int ret; + trace_rdev_del_mpath(&rdev->wiphy, dev, dst); + ret = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_change_mpath(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *dst, u8 *next_hop) { - return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); + int ret; + trace_rdev_change_mpath(&rdev->wiphy, dev, dst, next_hop); + ret = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *dst, u8 *next_hop, struct mpath_info *pinfo) { - return rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, pinfo); + int ret; + trace_rdev_get_mpath(&rdev->wiphy, dev, dst, next_hop); + ret = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, pinfo); + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); + return ret; + } static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, @@ -174,15 +267,23 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, u8 *next_hop, struct mpath_info *pinfo) { - return rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, + int ret; + trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop); + ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, pinfo); + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); + return ret; } static inline int rdev_get_mesh_config(struct cfg80211_registered_device *rdev, struct net_device *dev, struct mesh_config *conf) { - return rdev->ops->get_mesh_config(&rdev->wiphy, dev, conf); + int ret; + trace_rdev_get_mesh_config(&rdev->wiphy, dev); + ret = rdev->ops->get_mesh_config(&rdev->wiphy, dev, conf); + trace_rdev_return_int_mesh_config(&rdev->wiphy, ret, conf); + return ret; } static inline int @@ -190,7 +291,11 @@ rdev_update_mesh_config(struct cfg80211_registered_device *rdev, struct net_device *dev, u32 mask, const struct mesh_config *nconf) { - return rdev->ops->update_mesh_config(&rdev->wiphy, dev, mask, nconf); + int ret; + trace_rdev_update_mesh_config(&rdev->wiphy, dev, mask, nconf); + ret = rdev->ops->update_mesh_config(&rdev->wiphy, dev, mask, nconf); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_join_mesh(struct cfg80211_registered_device *rdev, @@ -198,14 +303,22 @@ static inline int rdev_join_mesh(struct cfg80211_registered_device *rdev, const struct mesh_config *conf, const struct mesh_setup *setup) { - return rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); + int ret; + trace_rdev_join_mesh(&rdev->wiphy, dev, conf, setup); + ret = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev, struct net_device *dev) { - return rdev->ops->leave_mesh(&rdev->wiphy, dev); + int ret; + trace_rdev_leave_mesh(&rdev->wiphy, dev); + ret = rdev->ops->leave_mesh(&rdev->wiphy, dev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, @@ -213,7 +326,11 @@ static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, struct bss_parameters *params) { - return rdev->ops->change_bss(&rdev->wiphy, dev, params); + int ret; + trace_rdev_change_bss(&rdev->wiphy, dev, params); + ret = rdev->ops->change_bss(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev, @@ -221,7 +338,11 @@ static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev, struct ieee80211_txq_params *params) { - return rdev->ops->set_txq_params(&rdev->wiphy, dev, params); + int ret; + trace_rdev_set_txq_params(&rdev->wiphy, dev, params); + ret = rdev->ops->set_txq_params(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -229,7 +350,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan) { - return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, dev, chan); + int ret; + trace_rdev_libertas_set_mesh_channel(&rdev->wiphy, dev, chan); + ret = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, dev, chan); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -237,97 +362,154 @@ rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { - return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, - channel_type); + int ret; + trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type); + ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_scan(struct cfg80211_registered_device *rdev, struct cfg80211_scan_request *request) { - return rdev->ops->scan(&rdev->wiphy, request); + int ret; + trace_rdev_scan(&rdev->wiphy, request); + ret = rdev->ops->scan(&rdev->wiphy, request); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_auth_request *req) { - return rdev->ops->auth(&rdev->wiphy, dev, req); + int ret; + trace_rdev_auth(&rdev->wiphy, dev, req); + ret = rdev->ops->auth(&rdev->wiphy, dev, req); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_assoc_request *req) { - return rdev->ops->assoc(&rdev->wiphy, dev, req); + int ret; + trace_rdev_assoc(&rdev->wiphy, dev, req); + ret = rdev->ops->assoc(&rdev->wiphy, dev, req); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_deauth_request *req) { - return rdev->ops->deauth(&rdev->wiphy, dev, req); + int ret; + trace_rdev_deauth(&rdev->wiphy, dev, req); + ret = rdev->ops->deauth(&rdev->wiphy, dev, req); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_disassoc_request *req) { - return rdev->ops->disassoc(&rdev->wiphy, dev, req); + int ret; + trace_rdev_disassoc(&rdev->wiphy, dev, req); + ret = rdev->ops->disassoc(&rdev->wiphy, dev, req); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *sme) { - return rdev->ops->connect(&rdev->wiphy, dev, sme); + int ret; + trace_rdev_connect(&rdev->wiphy, dev, sme); + ret = rdev->ops->connect(&rdev->wiphy, dev, sme); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_disconnect(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 reason_code) { - return rdev->ops->disconnect(&rdev->wiphy, dev, reason_code); + int ret; + trace_rdev_disconnect(&rdev->wiphy, dev, reason_code); + ret = rdev->ops->disconnect(&rdev->wiphy, dev, reason_code); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_ibss_params *params) { - return rdev->ops->join_ibss(&rdev->wiphy, dev, params); + int ret; + trace_rdev_join_ibss(&rdev->wiphy, dev, params); + ret = rdev->ops->join_ibss(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev) { - return rdev->ops->leave_ibss(&rdev->wiphy, dev); + int ret; + trace_rdev_leave_ibss(&rdev->wiphy, dev); + ret = rdev->ops->leave_ibss(&rdev->wiphy, dev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) { - return rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + int ret; + trace_rdev_set_wiphy_params(&rdev->wiphy, changed); + ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, enum nl80211_tx_power_setting type, int mbm) { - return rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); + int ret; + trace_rdev_set_tx_power(&rdev->wiphy, type, mbm); + ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, int *dbm) { - return rdev->ops->get_tx_power(&rdev->wiphy, dbm); + int ret; + trace_rdev_get_tx_power(&rdev->wiphy); + ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm); + trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); + return ret; } static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *addr) { - return rdev->ops->set_wds_peer(&rdev->wiphy, dev, addr); + int ret; + trace_rdev_set_wds_peer(&rdev->wiphy, dev, addr); + ret = rdev->ops->set_wds_peer(&rdev->wiphy, dev, addr); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) { + trace_rdev_rfkill_poll(&rdev->wiphy); rdev->ops->rfkill_poll(&rdev->wiphy); + trace_rdev_return_void(&rdev->wiphy); } @@ -335,7 +517,11 @@ static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev, void *data, int len) { - return rdev->ops->testmode_cmd(&rdev->wiphy, data, len); + int ret; + trace_rdev_testmode_cmd(&rdev->wiphy); + ret = rdev->ops->testmode_cmd(&rdev->wiphy, data, len); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev, @@ -343,8 +529,11 @@ static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev, struct netlink_callback *cb, void *data, int len) { - return rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, data, - len); + int ret; + trace_rdev_testmode_dump(&rdev->wiphy); + ret = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, data, len); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } #endif @@ -353,34 +542,57 @@ rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *peer, const struct cfg80211_bitrate_mask *mask) { - return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); + int ret; + trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask); + ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_dump_survey(struct cfg80211_registered_device *rdev, struct net_device *netdev, int idx, struct survey_info *info) { - return rdev->ops->dump_survey(&rdev->wiphy, netdev, idx, info); + int ret; + trace_rdev_dump_survey(&rdev->wiphy, netdev, idx); + ret = rdev->ops->dump_survey(&rdev->wiphy, netdev, idx, info); + if (ret < 0) + trace_rdev_return_int(&rdev->wiphy, ret); + else + trace_rdev_return_int_survey_info(&rdev->wiphy, ret, info); + return ret; } static inline int rdev_set_pmksa(struct cfg80211_registered_device *rdev, struct net_device *netdev, struct cfg80211_pmksa *pmksa) { - return rdev->ops->set_pmksa(&rdev->wiphy, netdev, pmksa); + int ret; + trace_rdev_set_pmksa(&rdev->wiphy, netdev, pmksa); + ret = rdev->ops->set_pmksa(&rdev->wiphy, netdev, pmksa); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_del_pmksa(struct cfg80211_registered_device *rdev, struct net_device *netdev, struct cfg80211_pmksa *pmksa) { - return rdev->ops->del_pmksa(&rdev->wiphy, netdev, pmksa); + int ret; + trace_rdev_del_pmksa(&rdev->wiphy, netdev, pmksa); + ret = rdev->ops->del_pmksa(&rdev->wiphy, netdev, pmksa); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_flush_pmksa(struct cfg80211_registered_device *rdev, struct net_device *netdev) { - return rdev->ops->flush_pmksa(&rdev->wiphy, netdev); + int ret; + trace_rdev_flush_pmksa(&rdev->wiphy, netdev); + ret = rdev->ops->flush_pmksa(&rdev->wiphy, netdev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int @@ -390,15 +602,24 @@ rdev_remain_on_channel(struct cfg80211_registered_device *rdev, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - return rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, + int ret; + trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, + duration); + ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, duration, cookie); + trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); + return ret; } static inline int rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u64 cookie) { - return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); + int ret; + trace_rdev_cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); + ret = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, @@ -409,72 +630,113 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, + int ret; + trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, + channel_type_valid, wait, no_cck, dont_wait_for_ack); + ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, channel_type_valid, wait, buf, len, no_cck, dont_wait_for_ack, cookie); + trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); + return ret; } static inline int rdev_mgmt_tx_cancel_wait(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u64 cookie) { - return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); + int ret; + trace_rdev_mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); + ret = rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_power_mgmt(struct cfg80211_registered_device *rdev, struct net_device *dev, bool enabled, int timeout) { - return rdev->ops->set_power_mgmt(&rdev->wiphy, dev, enabled, timeout); + int ret; + trace_rdev_set_power_mgmt(&rdev->wiphy, dev, enabled, timeout); + ret = rdev->ops->set_power_mgmt(&rdev->wiphy, dev, enabled, timeout); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev, struct net_device *dev, s32 rssi_thold, u32 rssi_hyst) { - return rdev->ops->set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold, - rssi_hyst); + int ret; + trace_rdev_set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold, + rssi_hyst); + ret = rdev->ops->set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold, + rssi_hyst); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev, struct net_device *dev, u32 rate, u32 pkts, u32 intvl) { - return rdev->ops->set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, + int ret; + trace_rdev_set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, intvl); + ret = rdev->ops->set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, intvl); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline void rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u16 frame_type, bool reg) { - rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, - reg); + trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); + rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); + trace_rdev_return_void(&rdev->wiphy); } static inline int rdev_set_antenna(struct cfg80211_registered_device *rdev, u32 tx_ant, u32 rx_ant) { - return rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); + int ret; + trace_rdev_set_antenna(&rdev->wiphy, tx_ant, rx_ant); + ret = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev, u32 *tx_ant, u32 *rx_ant) { - return rdev->ops->get_antenna(&rdev->wiphy, tx_ant, rx_ant); + int ret; + trace_rdev_get_antenna(&rdev->wiphy); + ret = rdev->ops->get_antenna(&rdev->wiphy, tx_ant, rx_ant); + if (ret) + trace_rdev_return_int(&rdev->wiphy, ret); + else + trace_rdev_return_int_tx_rx(&rdev->wiphy, ret, *tx_ant, + *rx_ant); + return ret; } static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, u32 tx, u32 rx) { - return rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); + int ret; + trace_rdev_set_ringparam(&rdev->wiphy, tx, rx); + ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) { + trace_rdev_get_ringparam(&rdev->wiphy); rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); + trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max); } static inline int @@ -482,20 +744,32 @@ rdev_sched_scan_start(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_sched_scan_request *request) { - return rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); + int ret; + trace_rdev_sched_scan_start(&rdev->wiphy, dev, request); + ret = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_sched_scan_stop(struct cfg80211_registered_device *rdev, struct net_device *dev) { - return rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + int ret; + trace_rdev_sched_scan_stop(&rdev->wiphy, dev); + ret = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_gtk_rekey_data *data) { - return rdev->ops->set_rekey_data(&rdev->wiphy, dev, data); + int ret; + trace_rdev_set_rekey_data(&rdev->wiphy, dev); + ret = rdev->ops->set_rekey_data(&rdev->wiphy, dev, data); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, @@ -503,56 +777,85 @@ static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, u8 action_code, u8 dialog_token, u16 status_code, const u8 *buf, size_t len) { - return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, buf, len); + int ret; + trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); + ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_tdls_oper(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *peer, enum nl80211_tdls_operation oper) { - return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, oper); + int ret; + trace_rdev_tdls_oper(&rdev->wiphy, dev, peer, oper); + ret = rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, oper); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_probe_client(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *peer, u64 *cookie) { - return rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie); + int ret; + trace_rdev_probe_client(&rdev->wiphy, dev, peer); + ret = rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie); + trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); + return ret; } static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 noack_map) { - return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map); + int ret; + trace_rdev_set_noack_map(&rdev->wiphy, dev, noack_map); + ret = rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline int rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, struct net_device *dev, int sset) { - return rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); + int ret; + trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset); + ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; } static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ethtool_stats *stats, u64 *data) { + trace_rdev_get_et_stats(&rdev->wiphy, dev); rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); + trace_rdev_return_void(&rdev->wiphy); } static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, struct net_device *dev, u32 sset, u8 *data) { + trace_rdev_get_et_strings(&rdev->wiphy, dev, sset); rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); + trace_rdev_return_void(&rdev->wiphy); } static inline struct ieee80211_channel *rdev_get_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, enum nl80211_channel_type *type) { - return rdev->ops->get_channel(&rdev->wiphy, wdev, type); + struct ieee80211_channel *ret; + trace_rdev_get_channel(&rdev->wiphy, wdev); + ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type); + trace_rdev_return_channel(&rdev->wiphy, ret, *type); + return ret; } #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.c b/net/wireless/trace.c new file mode 100644 index 000000000000..95f997fad755 --- /dev/null +++ b/net/wireless/trace.c @@ -0,0 +1,7 @@ +#include + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/net/wireless/trace.h b/net/wireless/trace.h new file mode 100644 index 000000000000..0940e9103776 --- /dev/null +++ b/net/wireless/trace.h @@ -0,0 +1,1750 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cfg80211 + +#if !defined(__RDEV_OPS_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __RDEV_OPS_TRACE + +#include + +#include +#include +#include "core.h" + +#define MAC_ENTRY(entry_mac) __array(u8, entry_mac, ETH_ALEN) +#define MAC_ASSIGN(entry_mac, given_mac) do { \ + if (given_mac) \ + memcpy(__entry->entry_mac, given_mac, ETH_ALEN); \ + else \ + memset(__entry->entry_mac, 0, ETH_ALEN); \ + } while (0) +#define MAC_PR_FMT "%pM" +#define MAC_PR_ARG(entry_mac) (__entry->entry_mac) + +#define WIPHY_ENTRY MAC_ENTRY(wiphy_mac) +#define WIPHY_ASSIGN MAC_ASSIGN(wiphy_mac, wiphy->perm_addr) +#define WIPHY_PR_FMT "wiphy " MAC_PR_FMT +#define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac) + +#define WDEV_ENTRY __field(u32, id) +#define WDEV_ASSIGN (__entry->id) = (wdev->identifier) +#define WDEV_PR_FMT ", wdev id: %u" +#define WDEV_PR_ARG (__entry->id) + +#define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \ + MAC_ENTRY(netdev_addr) \ + __field(int, ifindex) +#define NETDEV_ASSIGN \ + do { \ + memcpy(__entry->name, netdev->name, IFNAMSIZ); \ + MAC_ASSIGN(netdev_addr, netdev->dev_addr); \ + (__entry->ifindex) = (netdev->ifindex); \ + } while (0) +#define NETDEV_PR_FMT ", netdev - name: %s, addr: " MAC_PR_FMT \ + ", intf index: %d" +#define NETDEV_PR_ARG (__entry->name), MAC_PR_ARG(netdev_addr), \ + (__entry->ifindex) + +#define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout) \ + __field(u16, dot11MeshConfirmTimeout) \ + __field(u16, dot11MeshHoldingTimeout) \ + __field(u16, dot11MeshMaxPeerLinks) \ + __field(u8, dot11MeshMaxRetries) \ + __field(u8, dot11MeshTTL) \ + __field(u8, element_ttl) \ + __field(bool, auto_open_plinks) \ + __field(u32, dot11MeshNbrOffsetMaxNeighbor) \ + __field(u8, dot11MeshHWMPmaxPREQretries) \ + __field(u32, path_refresh_time) \ + __field(u32, dot11MeshHWMPactivePathTimeout) \ + __field(u16, min_discovery_timeout) \ + __field(u16, dot11MeshHWMPpreqMinInterval) \ + __field(u16, dot11MeshHWMPperrMinInterval) \ + __field(u16, dot11MeshHWMPnetDiameterTraversalTime) \ + __field(u8, dot11MeshHWMPRootMode) \ + __field(u16, dot11MeshHWMPRannInterval) \ + __field(bool, dot11MeshGateAnnouncementProtocol) \ + __field(bool, dot11MeshForwarding) \ + __field(s32, rssi_threshold) \ + __field(u16, ht_opmode) \ + __field(u32, dot11MeshHWMPactivePathToRootTimeout) \ + __field(u16, dot11MeshHWMProotInterval) \ + __field(u16, dot11MeshHWMPconfirmationInterval) +#define MESH_CFG_ASSIGN \ + do { \ + __entry->dot11MeshRetryTimeout = conf->dot11MeshRetryTimeout; \ + __entry->dot11MeshConfirmTimeout = \ + conf->dot11MeshConfirmTimeout; \ + __entry->dot11MeshHoldingTimeout = \ + conf->dot11MeshHoldingTimeout; \ + __entry->dot11MeshMaxPeerLinks = conf->dot11MeshMaxPeerLinks; \ + __entry->dot11MeshMaxRetries = conf->dot11MeshMaxRetries; \ + __entry->dot11MeshTTL = conf->dot11MeshTTL; \ + __entry->element_ttl = conf->element_ttl; \ + __entry->auto_open_plinks = conf->auto_open_plinks; \ + __entry->dot11MeshNbrOffsetMaxNeighbor = \ + conf->dot11MeshNbrOffsetMaxNeighbor; \ + __entry->dot11MeshHWMPmaxPREQretries = \ + conf->dot11MeshHWMPmaxPREQretries; \ + __entry->path_refresh_time = conf->path_refresh_time; \ + __entry->dot11MeshHWMPactivePathTimeout = \ + conf->dot11MeshHWMPactivePathTimeout; \ + __entry->min_discovery_timeout = conf->min_discovery_timeout; \ + __entry->dot11MeshHWMPpreqMinInterval = \ + conf->dot11MeshHWMPpreqMinInterval; \ + __entry->dot11MeshHWMPperrMinInterval = \ + conf->dot11MeshHWMPperrMinInterval; \ + __entry->dot11MeshHWMPnetDiameterTraversalTime = \ + conf->dot11MeshHWMPnetDiameterTraversalTime; \ + __entry->dot11MeshHWMPRootMode = conf->dot11MeshHWMPRootMode; \ + __entry->dot11MeshHWMPRannInterval = \ + conf->dot11MeshHWMPRannInterval; \ + __entry->dot11MeshGateAnnouncementProtocol = \ + conf->dot11MeshGateAnnouncementProtocol; \ + __entry->dot11MeshForwarding = conf->dot11MeshForwarding; \ + __entry->rssi_threshold = conf->rssi_threshold; \ + __entry->ht_opmode = conf->ht_opmode; \ + __entry->dot11MeshHWMPactivePathToRootTimeout = \ + conf->dot11MeshHWMPactivePathToRootTimeout; \ + __entry->dot11MeshHWMProotInterval = \ + conf->dot11MeshHWMProotInterval; \ + __entry->dot11MeshHWMPconfirmationInterval = \ + conf->dot11MeshHWMPconfirmationInterval; \ + } while (0) + +#define CHAN_ENTRY __field(enum ieee80211_band, band) \ + __field(u16, center_freq) +#define CHAN_ASSIGN(chan) \ + do { \ + if (chan) { \ + __entry->band = chan->band; \ + __entry->center_freq = chan->center_freq; \ + } else { \ + __entry->band = 0; \ + __entry->center_freq = 0; \ + } \ + } while (0) +#define CHAN_PR_FMT ", band: %d, freq: %u" +#define CHAN_PR_ARG __entry->band, __entry->center_freq + +#define SINFO_ENTRY __field(int, generation) \ + __field(u32, connected_time) \ + __field(u32, inactive_time) \ + __field(u32, rx_bytes) \ + __field(u32, tx_bytes) \ + __field(u32, rx_packets) \ + __field(u32, tx_packets) \ + __field(u32, tx_retries) \ + __field(u32, tx_failed) \ + __field(u32, rx_dropped_misc) \ + __field(u32, beacon_loss_count) \ + __field(u16, llid) \ + __field(u16, plid) \ + __field(u8, plink_state) +#define SINFO_ASSIGN \ + do { \ + __entry->generation = sinfo->generation; \ + __entry->connected_time = sinfo->connected_time; \ + __entry->inactive_time = sinfo->inactive_time; \ + __entry->rx_bytes = sinfo->rx_bytes; \ + __entry->tx_bytes = sinfo->tx_bytes; \ + __entry->rx_packets = sinfo->rx_packets; \ + __entry->tx_packets = sinfo->tx_packets; \ + __entry->tx_retries = sinfo->tx_retries; \ + __entry->tx_failed = sinfo->tx_failed; \ + __entry->rx_dropped_misc = sinfo->rx_dropped_misc; \ + __entry->beacon_loss_count = sinfo->beacon_loss_count; \ + __entry->llid = sinfo->llid; \ + __entry->plid = sinfo->plid; \ + __entry->plink_state = sinfo->plink_state; \ + } while (0) + +#define BOOL_TO_STR(bo) (bo) ? "true" : "false" + +/************************************************************* + * rdev->ops traces * + *************************************************************/ + +TRACE_EVENT(rdev_suspend, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_wowlan *wow), + TP_ARGS(wiphy, wow), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(bool, any) + __field(bool, disconnect) + __field(bool, magic_pkt) + __field(bool, gtk_rekey_failure) + __field(bool, eap_identity_req) + __field(bool, four_way_handshake) + __field(bool, rfkill_release) + __field(bool, valid_wow) + ), + TP_fast_assign( + WIPHY_ASSIGN; + if (wow) { + __entry->any = wow->any; + __entry->disconnect = wow->disconnect; + __entry->magic_pkt = wow->magic_pkt; + __entry->gtk_rekey_failure = wow->gtk_rekey_failure; + __entry->eap_identity_req = wow->eap_identity_req; + __entry->four_way_handshake = wow->four_way_handshake; + __entry->rfkill_release = wow->rfkill_release; + __entry->valid_wow = true; + } else { + __entry->valid_wow = false; + } + ), + TP_printk(WIPHY_PR_FMT ", wow%s - any: %d, disconnect: %d, " + "magic pkt: %d, gtk rekey failure: %d, eap identify req: %d, " + "four way handshake: %d, rfkill release: %d.", + WIPHY_PR_ARG, __entry->valid_wow ? "" : "(Not configured!)", + __entry->any, __entry->disconnect, __entry->magic_pkt, + __entry->gtk_rekey_failure, __entry->eap_identity_req, + __entry->four_way_handshake, __entry->rfkill_release) +); + +TRACE_EVENT(rdev_return_int, + TP_PROTO(struct wiphy *wiphy, int ret), + TP_ARGS(wiphy, ret), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, ret) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->ret = ret; + ), + TP_printk(WIPHY_PR_FMT ", returned: %d", WIPHY_PR_ARG, __entry->ret) +); + +TRACE_EVENT(rdev_scan, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_scan_request *request), + TP_ARGS(wiphy, request), + TP_STRUCT__entry( + WIPHY_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG) +); + +DECLARE_EVENT_CLASS(wiphy_only_evt, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy), + TP_STRUCT__entry( + WIPHY_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_resume, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_return_void, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DECLARE_EVENT_CLASS(wiphy_enabled_evt, + TP_PROTO(struct wiphy *wiphy, bool enabled), + TP_ARGS(wiphy, enabled), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(bool, enabled) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->enabled = enabled; + ), + TP_printk(WIPHY_PR_FMT ", %senabled ", + WIPHY_PR_ARG, __entry->enabled ? "" : "not ") +); + +DEFINE_EVENT(wiphy_enabled_evt, rdev_set_wakeup, + TP_PROTO(struct wiphy *wiphy, bool enabled), + TP_ARGS(wiphy, enabled) +); + +TRACE_EVENT(rdev_add_virtual_intf, + TP_PROTO(struct wiphy *wiphy, char *name, enum nl80211_iftype type), + TP_ARGS(wiphy, name, type), + TP_STRUCT__entry( + WIPHY_ENTRY + __string(vir_intf_name, name ? name : "") + __field(enum nl80211_iftype, type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __assign_str(vir_intf_name, name ? name : ""); + __entry->type = type; + ), + TP_printk(WIPHY_PR_FMT ", virtual intf name: %s, type: %d", + WIPHY_PR_ARG, __get_str(vir_intf_name), __entry->type) +); + +DECLARE_EVENT_CLASS(wiphy_wdev_evt, + 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) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_del_virtual_intf, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + +TRACE_EVENT(rdev_change_virtual_intf, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + enum nl80211_iftype type), + TP_ARGS(wiphy, netdev, type), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(enum nl80211_iftype, type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->type = type; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", type: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type) +); + +DECLARE_EVENT_CLASS(key_handle, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr), + TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(mac_addr) + __field(u8, key_index) + __field(bool, pairwise) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(mac_addr, mac_addr); + __entry->key_index = key_index; + __entry->pairwise = pairwise; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, + BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) +); + +DEFINE_EVENT(key_handle, rdev_add_key, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr), + TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) +); + +DEFINE_EVENT(key_handle, rdev_get_key, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr), + TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) +); + +DEFINE_EVENT(key_handle, rdev_del_key, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr), + TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) +); + +TRACE_EVENT(rdev_set_default_key, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool unicast, bool multicast), + TP_ARGS(wiphy, netdev, key_index, unicast, multicast), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u8, key_index) + __field(bool, unicast) + __field(bool, multicast) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->key_index = key_index; + __entry->unicast = unicast; + __entry->multicast = multicast; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, + BOOL_TO_STR(__entry->unicast), + BOOL_TO_STR(__entry->multicast)) +); + +TRACE_EVENT(rdev_set_default_mgmt_key, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index), + TP_ARGS(wiphy, netdev, key_index), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u8, key_index) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->key_index = key_index; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index) +); + +TRACE_EVENT(rdev_start_ap, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_ap_settings *settings), + TP_ARGS(wiphy, netdev, settings), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + CHAN_ENTRY + __field(int, beacon_interval) + __field(int, dtim_period) + __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) + __field(enum nl80211_hidden_ssid, hidden_ssid) + __field(u32, wpa_ver) + __field(bool, privacy) + __field(enum nl80211_auth_type, auth_type) + __field(int, inactivity_timeout) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + CHAN_ASSIGN(settings->channel); + __entry->beacon_interval = settings->beacon_interval; + __entry->dtim_period = settings->dtim_period; + __entry->hidden_ssid = settings->hidden_ssid; + __entry->wpa_ver = settings->crypto.wpa_versions; + __entry->privacy = settings->privacy; + __entry->auth_type = settings->auth_type; + __entry->inactivity_timeout = settings->inactivity_timeout; + memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); + memcpy(__entry->ssid, settings->ssid, settings->ssid_len); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, " + CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, " + "hidden ssid: %d, wpa versions: %u, privacy: %s, " + "auth type: %d, inactivity timeout: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG, + __entry->beacon_interval, __entry->dtim_period, + __entry->hidden_ssid, __entry->wpa_ver, + BOOL_TO_STR(__entry->privacy), __entry->auth_type, + __entry->inactivity_timeout) +); + +TRACE_EVENT(rdev_change_beacon, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_beacon_data *info), + TP_ARGS(wiphy, netdev, info), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __dynamic_array(u8, head, info ? info->head_len : 0) + __dynamic_array(u8, tail, info ? info->tail_len : 0) + __dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0) + __dynamic_array(u8, proberesp_ies, + info ? info->proberesp_ies_len : 0) + __dynamic_array(u8, assocresp_ies, + info ? info->assocresp_ies_len : 0) + __dynamic_array(u8, probe_resp, info ? info->probe_resp_len : 0) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + if (info) { + if (info->head) + memcpy(__get_dynamic_array(head), info->head, + info->head_len); + if (info->tail) + memcpy(__get_dynamic_array(tail), info->tail, + info->tail_len); + if (info->beacon_ies) + memcpy(__get_dynamic_array(beacon_ies), + info->beacon_ies, info->beacon_ies_len); + if (info->proberesp_ies) + memcpy(__get_dynamic_array(proberesp_ies), + info->proberesp_ies, + info->proberesp_ies_len); + if (info->assocresp_ies) + memcpy(__get_dynamic_array(assocresp_ies), + info->assocresp_ies, + info->assocresp_ies_len); + if (info->probe_resp) + memcpy(__get_dynamic_array(probe_resp), + info->probe_resp, info->probe_resp_len); + } + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) +); + +DECLARE_EVENT_CLASS(wiphy_netdev_evt, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_get_mesh_config, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_mesh, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + +DECLARE_EVENT_CLASS(station_add_change, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac, + struct station_parameters *params), + TP_ARGS(wiphy, netdev, mac, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(sta_mac) + __field(u32, sta_flags_mask) + __field(u32, sta_flags_set) + __field(u32, sta_modify_mask) + __field(int, listen_interval) + __field(u16, aid) + __field(u8, plink_action) + __field(u8, plink_state) + __field(u8, uapsd_queues) + __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap)) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(sta_mac, mac); + __entry->sta_flags_mask = params->sta_flags_mask; + __entry->sta_flags_set = params->sta_flags_set; + __entry->sta_modify_mask = params->sta_modify_mask; + __entry->listen_interval = params->listen_interval; + __entry->aid = params->aid; + __entry->plink_action = params->plink_action; + __entry->plink_state = params->plink_state; + __entry->uapsd_queues = params->uapsd_queues; + memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap)); + if (params->ht_capa) + memcpy(__entry->ht_capa, params->ht_capa, + sizeof(struct ieee80211_ht_cap)); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + ", station flags mask: %u, station flags set: %u, " + "station modify mask: %u, listen interval: %d, aid: %u, " + "plink action: %u, plink state: %u, uapsd queues: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), + __entry->sta_flags_mask, __entry->sta_flags_set, + __entry->sta_modify_mask, __entry->listen_interval, + __entry->aid, __entry->plink_action, __entry->plink_state, + __entry->uapsd_queues) +); + +DEFINE_EVENT(station_add_change, rdev_add_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac, + struct station_parameters *params), + TP_ARGS(wiphy, netdev, mac, params) +); + +DEFINE_EVENT(station_add_change, rdev_change_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac, + struct station_parameters *params), + TP_ARGS(wiphy, netdev, mac, params) +); + +DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), + TP_ARGS(wiphy, netdev, mac), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(sta_mac) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(sta_mac, mac); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mac: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) +); + +DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), + TP_ARGS(wiphy, netdev, mac) +); + +DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), + TP_ARGS(wiphy, netdev, mac) +); + +DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_mpath, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), + TP_ARGS(wiphy, netdev, mac) +); + +DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_set_wds_peer, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), + TP_ARGS(wiphy, netdev, mac) +); + +TRACE_EVENT(rdev_dump_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, + u8 *mac), + TP_ARGS(wiphy, netdev, idx, mac), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(sta_mac) + __field(int, idx) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(sta_mac, mac); + __entry->idx = idx; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), + __entry->idx) +); + +TRACE_EVENT(rdev_return_int_station_info, + TP_PROTO(struct wiphy *wiphy, int ret, struct station_info *sinfo), + TP_ARGS(wiphy, ret, sinfo), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, ret) + SINFO_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->ret = ret; + SINFO_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT ", returned %d" , + WIPHY_PR_ARG, __entry->ret) +); + +DECLARE_EVENT_CLASS(mpath_evt, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst, + u8 *next_hop), + TP_ARGS(wiphy, netdev, dst, next_hop), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(dst) + MAC_ENTRY(next_hop) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(dst, dst); + MAC_ASSIGN(next_hop, next_hop); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst), + MAC_PR_ARG(next_hop)) +); + +DEFINE_EVENT(mpath_evt, rdev_add_mpath, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst, + u8 *next_hop), + TP_ARGS(wiphy, netdev, dst, next_hop) +); + +DEFINE_EVENT(mpath_evt, rdev_change_mpath, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst, + u8 *next_hop), + TP_ARGS(wiphy, netdev, dst, next_hop) +); + +DEFINE_EVENT(mpath_evt, rdev_get_mpath, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst, + u8 *next_hop), + TP_ARGS(wiphy, netdev, dst, next_hop) +); + +TRACE_EVENT(rdev_dump_mpath, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, + u8 *dst, u8 *next_hop), + TP_ARGS(wiphy, netdev, idx, dst, next_hop), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(dst) + MAC_ENTRY(next_hop) + __field(int, idx) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(dst, dst); + MAC_ASSIGN(next_hop, next_hop); + __entry->idx = idx; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d, destination: " + MAC_PR_FMT ", next hop: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), + MAC_PR_ARG(next_hop)) +); + +TRACE_EVENT(rdev_return_int_mpath_info, + TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo), + TP_ARGS(wiphy, ret, pinfo), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, ret) + __field(int, generation) + __field(u32, filled) + __field(u32, frame_qlen) + __field(u32, sn) + __field(u32, metric) + __field(u32, exptime) + __field(u32, discovery_timeout) + __field(u8, discovery_retries) + __field(u8, flags) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->ret = ret; + __entry->generation = pinfo->generation; + __entry->filled = pinfo->filled; + __entry->frame_qlen = pinfo->frame_qlen; + __entry->sn = pinfo->sn; + __entry->metric = pinfo->metric; + __entry->exptime = pinfo->exptime; + __entry->discovery_timeout = pinfo->discovery_timeout; + __entry->discovery_retries = pinfo->discovery_retries; + __entry->flags = pinfo->flags; + ), + TP_printk(WIPHY_PR_FMT ", returned %d. mpath info - generation: %d, " + "filled: %u, frame qlen: %u, sn: %u, metric: %u, exptime: %u," + " discovery timeout: %u, discovery retries: %u, flags: %u", + WIPHY_PR_ARG, __entry->ret, __entry->generation, + __entry->filled, __entry->frame_qlen, __entry->sn, + __entry->metric, __entry->exptime, __entry->discovery_timeout, + __entry->discovery_retries, __entry->flags) +); + +TRACE_EVENT(rdev_return_int_mesh_config, + TP_PROTO(struct wiphy *wiphy, int ret, struct mesh_config *conf), + TP_ARGS(wiphy, ret, conf), + TP_STRUCT__entry( + WIPHY_ENTRY + MESH_CFG_ENTRY + __field(int, ret) + ), + TP_fast_assign( + WIPHY_ASSIGN; + MESH_CFG_ASSIGN; + __entry->ret = ret; + ), + TP_printk(WIPHY_PR_FMT ", returned: %d", + WIPHY_PR_ARG, __entry->ret) +); + +TRACE_EVENT(rdev_update_mesh_config, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 mask, + const struct mesh_config *conf), + TP_ARGS(wiphy, netdev, mask, conf), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MESH_CFG_ENTRY + __field(u32, mask) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MESH_CFG_ASSIGN; + __entry->mask = mask; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mask: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask) +); + +TRACE_EVENT(rdev_join_mesh, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + const struct mesh_config *conf, + const struct mesh_setup *setup), + TP_ARGS(wiphy, netdev, conf, setup), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MESH_CFG_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MESH_CFG_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG) +); + +TRACE_EVENT(rdev_change_bss, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct bss_parameters *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(int, use_cts_prot) + __field(int, use_short_preamble) + __field(int, use_short_slot_time) + __field(int, ap_isolate) + __field(int, ht_opmode) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->use_cts_prot = params->use_cts_prot; + __entry->use_short_preamble = params->use_short_preamble; + __entry->use_short_slot_time = params->use_short_slot_time; + __entry->ap_isolate = params->ap_isolate; + __entry->ht_opmode = params->ht_opmode; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", use cts prot: %d, " + "use short preamble: %d, use short slot time: %d, " + "ap isolate: %d, ht opmode: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot, + __entry->use_short_preamble, __entry->use_short_slot_time, + __entry->ap_isolate, __entry->ht_opmode) +); + +TRACE_EVENT(rdev_set_txq_params, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct ieee80211_txq_params *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(enum nl80211_ac, ac) + __field(u16, txop) + __field(u16, cwmin) + __field(u16, cwmax) + __field(u8, aifs) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->ac = params->ac; + __entry->txop = params->txop; + __entry->cwmin = params->cwmin; + __entry->cwmax = params->cwmax; + __entry->aifs = params->aifs; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop, + __entry->cwmin, __entry->cwmax, __entry->aifs) +); + +TRACE_EVENT(rdev_libertas_set_mesh_channel, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct ieee80211_channel *chan), + TP_ARGS(wiphy, netdev, chan), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + CHAN_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + CHAN_ASSIGN(chan); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT CHAN_PR_FMT, WIPHY_PR_ARG, + NETDEV_PR_ARG, CHAN_PR_ARG) +); + +TRACE_EVENT(rdev_set_monitor_channel, + TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, + enum nl80211_channel_type chan_type), + TP_ARGS(wiphy, chan, chan_type), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + __field(enum nl80211_channel_type, chan_type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(chan); + __entry->chan_type = chan_type; + ), + TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d", + WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type) +); + +TRACE_EVENT(rdev_auth, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_auth_request *req), + TP_ARGS(wiphy, netdev, req), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __field(enum nl80211_auth_type, auth_type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + if (req->bss) + MAC_ASSIGN(bssid, req->bss->bssid); + else + memset(__entry->bssid, 0, ETH_ALEN); + __entry->auth_type = req->auth_type; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type, + MAC_PR_ARG(bssid)) +); + +TRACE_EVENT(rdev_assoc, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_assoc_request *req), + TP_ARGS(wiphy, netdev, req), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + MAC_ENTRY(prev_bssid) + __field(bool, use_mfp) + __field(u32, flags) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + if (req->bss) + MAC_ASSIGN(bssid, req->bss->bssid); + else + memset(__entry->bssid, 0, ETH_ALEN); + MAC_ASSIGN(prev_bssid, req->prev_bssid); + __entry->use_mfp = req->use_mfp; + __entry->flags = req->flags; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), + MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp), + __entry->flags) +); + +TRACE_EVENT(rdev_deauth, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_deauth_request *req), + TP_ARGS(wiphy, netdev, req), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __field(u16, reason_code) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, req->bssid); + __entry->reason_code = req->reason_code; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), + __entry->reason_code) +); + +TRACE_EVENT(rdev_disassoc, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_disassoc_request *req), + TP_ARGS(wiphy, netdev, req), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __field(u16, reason_code) + __field(bool, local_state_change) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + if (req->bss) + MAC_ASSIGN(bssid, req->bss->bssid); + else + memset(__entry->bssid, 0, ETH_ALEN); + __entry->reason_code = req->reason_code; + __entry->local_state_change = req->local_state_change; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + ", reason: %u, local state change: %s", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), + __entry->reason_code, + BOOL_TO_STR(__entry->local_state_change)) +); + +TRACE_EVENT(rdev_mgmt_tx_cancel_wait, + TP_PROTO(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie), + TP_ARGS(wiphy, wdev, cookie), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + __field(u64, cookie) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + __entry->cookie = cookie; + ), + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu ", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) +); + +TRACE_EVENT(rdev_set_power_mgmt, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + bool enabled, int timeout), + TP_ARGS(wiphy, netdev, enabled, timeout), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(bool, enabled) + __field(int, timeout) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->enabled = enabled; + __entry->timeout = timeout; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", %senabled, timeout: %d ", + WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->enabled ? "" : "not ", __entry->timeout) +); + +TRACE_EVENT(rdev_connect, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_connect_params *sme), + TP_ARGS(wiphy, netdev, sme), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) + __field(enum nl80211_auth_type, auth_type) + __field(bool, privacy) + __field(u32, wpa_versions) + __field(u32, flags) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, sme->bssid); + memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); + memcpy(__entry->ssid, sme->ssid, sme->ssid_len); + __entry->auth_type = sme->auth_type; + __entry->privacy = sme->privacy; + __entry->wpa_versions = sme->crypto.wpa_versions; + __entry->flags = sme->flags; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT + ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, " + "flags: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid, + __entry->auth_type, BOOL_TO_STR(__entry->privacy), + __entry->wpa_versions, __entry->flags) +); + +TRACE_EVENT(rdev_set_cqm_rssi_config, + TP_PROTO(struct wiphy *wiphy, + struct net_device *netdev, s32 rssi_thold, + u32 rssi_hyst), + TP_ARGS(wiphy, netdev, rssi_thold, rssi_hyst), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(s32, rssi_thold) + __field(u32, rssi_hyst) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->rssi_thold = rssi_thold; + __entry->rssi_hyst = rssi_hyst; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT + ", rssi_thold: %d, rssi_hyst: %u ", + WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->rssi_thold, __entry->rssi_hyst) +); + +TRACE_EVENT(rdev_set_cqm_txe_config, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate, + u32 pkts, u32 intvl), + TP_ARGS(wiphy, netdev, rate, pkts, intvl), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u32, rate) + __field(u32, pkts) + __field(u32, intvl) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->rate = rate; + __entry->pkts = pkts; + __entry->intvl = intvl; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts, + __entry->intvl) +); + +TRACE_EVENT(rdev_disconnect, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u16 reason_code), + TP_ARGS(wiphy, netdev, reason_code), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u16, reason_code) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->reason_code = reason_code; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG, + NETDEV_PR_ARG, __entry->reason_code) +); + +TRACE_EVENT(rdev_join_ibss, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_ibss_params *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, params->bssid); + memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); + memcpy(__entry->ssid, params->ssid, params->ssid_len); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) +); + +TRACE_EVENT(rdev_set_wiphy_params, + TP_PROTO(struct wiphy *wiphy, u32 changed), + TP_ARGS(wiphy, changed), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(u32, changed) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->changed = changed; + ), + TP_printk(WIPHY_PR_FMT ", changed: %u", + WIPHY_PR_ARG, __entry->changed) +); + +TRACE_EVENT(rdev_set_tx_power, + TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type, + int mbm), + TP_ARGS(wiphy, type, mbm), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(enum nl80211_tx_power_setting, type) + __field(int, mbm) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->type = type; + __entry->mbm = mbm; + ), + TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d", + WIPHY_PR_ARG, __entry->type, __entry->mbm) +); + +TRACE_EVENT(rdev_return_int_int, + TP_PROTO(struct wiphy *wiphy, int func_ret, int func_fill), + TP_ARGS(wiphy, func_ret, func_fill), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, func_ret) + __field(int, func_fill) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->func_ret = func_ret; + __entry->func_fill = func_fill; + ), + TP_printk(WIPHY_PR_FMT ", function returns: %d, function filled: %d", + WIPHY_PR_ARG, __entry->func_ret, __entry->func_fill) +); + +#ifdef CONFIG_NL80211_TESTMODE +TRACE_EVENT(rdev_testmode_cmd, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy), + TP_STRUCT__entry( + WIPHY_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG) +); + +TRACE_EVENT(rdev_testmode_dump, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy), + TP_STRUCT__entry( + WIPHY_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG) +); +#endif /* CONFIG_NL80211_TESTMODE */ + +TRACE_EVENT(rdev_set_bitrate_mask, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + const u8 *peer, const struct cfg80211_bitrate_mask *mask), + TP_ARGS(wiphy, netdev, peer, mask), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", peer: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) +); + +TRACE_EVENT(rdev_mgmt_frame_register, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + u16 frame_type, bool reg), + TP_ARGS(wiphy, wdev, frame_type, reg), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + __field(u16, frame_type) + __field(bool, reg) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + __entry->frame_type = frame_type; + __entry->reg = reg; + ), + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", frame_type: %u, reg: %s ", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, + __entry->reg ? "true" : "false") +); + +TRACE_EVENT(rdev_return_int_tx_rx, + TP_PROTO(struct wiphy *wiphy, int ret, u32 tx, u32 rx), + TP_ARGS(wiphy, ret, tx, rx), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, ret) + __field(u32, tx) + __field(u32, rx) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->ret = ret; + __entry->tx = tx; + __entry->rx = rx; + ), + TP_printk(WIPHY_PR_FMT ", returned %d, tx: %u, rx: %u", + WIPHY_PR_ARG, __entry->ret, __entry->tx, __entry->rx) +); + +TRACE_EVENT(rdev_return_void_tx_rx, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 tx_max, + u32 rx, u32 rx_max), + TP_ARGS(wiphy, tx, tx_max, rx, rx_max), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(u32, tx) + __field(u32, tx_max) + __field(u32, rx) + __field(u32, rx_max) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->tx = tx; + __entry->tx_max = tx_max; + __entry->rx = rx; + __entry->rx_max = rx_max; + ), + TP_printk(WIPHY_PR_FMT ", tx: %u, tx_max: %u, rx: %u, rx_max: %u ", + WIPHY_PR_ARG, __entry->tx, __entry->tx_max, __entry->rx, + __entry->rx_max) +); + +DECLARE_EVENT_CLASS(tx_rx_evt, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), + TP_ARGS(wiphy, rx, tx), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(u32, tx) + __field(u32, rx) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->tx = tx; + __entry->rx = rx; + ), + TP_printk(WIPHY_PR_FMT ", tx: %u, rx: %u ", + WIPHY_PR_ARG, __entry->tx, __entry->rx) +); + +DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), + TP_ARGS(wiphy, rx, tx) +); + +DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), + TP_ARGS(wiphy, rx, tx) +); + +TRACE_EVENT(rdev_sched_scan_start, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_sched_scan_request *request), + TP_ARGS(wiphy, netdev, request), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG) +); + +TRACE_EVENT(rdev_tdls_mgmt, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, const u8 *buf, size_t len), + TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, + buf, len), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(u8, action_code) + __field(u8, dialog_token) + __field(u16, status_code) + __dynamic_array(u8, buf, len) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->action_code = action_code; + __entry->dialog_token = dialog_token; + __entry->status_code = status_code; + memcpy(__get_dynamic_array(buf), buf, len); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", action_code: %u, " + "dialog_token: %u, status_code: %u, buf: %#.2x ", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), + __entry->action_code, __entry->dialog_token, + __entry->status_code, ((u8 *)__get_dynamic_array(buf))[0]) +); + +TRACE_EVENT(rdev_dump_survey, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx), + TP_ARGS(wiphy, netdev, idx), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(int, idx) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->idx = idx; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx) +); + +TRACE_EVENT(rdev_return_int_survey_info, + TP_PROTO(struct wiphy *wiphy, int ret, struct survey_info *info), + TP_ARGS(wiphy, ret, info), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + __field(int, ret) + __field(u64, channel_time) + __field(u64, channel_time_busy) + __field(u64, channel_time_ext_busy) + __field(u64, channel_time_rx) + __field(u64, channel_time_tx) + __field(u32, filled) + __field(s8, noise) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(info->channel); + __entry->ret = ret; + __entry->channel_time = info->channel_time; + __entry->channel_time_busy = info->channel_time_busy; + __entry->channel_time_ext_busy = info->channel_time_ext_busy; + __entry->channel_time_rx = info->channel_time_rx; + __entry->channel_time_tx = info->channel_time_tx; + __entry->filled = info->filled; + __entry->noise = info->noise; + ), + TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT + ", channel time: %llu, channel time busy: %llu, " + "channel time extension busy: %llu, channel time rx: %llu, " + "channel time tx: %llu, filled: %u, noise: %d", + WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG, + __entry->channel_time, __entry->channel_time_busy, + __entry->channel_time_ext_busy, __entry->channel_time_rx, + __entry->channel_time_tx, __entry->filled, __entry->noise) +); + +TRACE_EVENT(rdev_tdls_oper, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u8 *peer, enum nl80211_tdls_operation oper), + TP_ARGS(wiphy, netdev, peer, oper), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(enum nl80211_tdls_operation, oper) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->oper = oper; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", oper: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper) +); + +DECLARE_EVENT_CLASS(rdev_pmksa, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa), + TP_ARGS(wiphy, netdev, pmksa), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(bssid) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, pmksa->bssid); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid)) +); + +TRACE_EVENT(rdev_probe_client, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + const u8 *peer), + TP_ARGS(wiphy, netdev, peer), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) +); + +DEFINE_EVENT(rdev_pmksa, rdev_set_pmksa, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa), + TP_ARGS(wiphy, netdev, pmksa) +); + +DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa), + TP_ARGS(wiphy, netdev, pmksa) +); + +TRACE_EVENT(rdev_remain_on_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, unsigned int duration), + TP_ARGS(wiphy, wdev, chan, channel_type, duration), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + CHAN_ENTRY + __field(enum nl80211_channel_type, channel_type) + __field(unsigned int, duration) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + CHAN_ASSIGN(chan); + __entry->channel_type = channel_type; + __entry->duration = duration; + ), + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u", + WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type, + __entry->duration) +); + +TRACE_EVENT(rdev_return_int_cookie, + TP_PROTO(struct wiphy *wiphy, int ret, u64 cookie), + TP_ARGS(wiphy, ret, cookie), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, ret) + __field(u64, cookie) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->ret = ret; + __entry->cookie = cookie; + ), + TP_printk(WIPHY_PR_FMT ", returned %d, cookie: %llu", + WIPHY_PR_ARG, __entry->ret, __entry->cookie) +); + +TRACE_EVENT(rdev_cancel_remain_on_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie), + TP_ARGS(wiphy, wdev, cookie), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + __field(u64, cookie) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + __entry->cookie = cookie; + ), + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) +); + +TRACE_EVENT(rdev_mgmt_tx, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, bool no_cck, + bool dont_wait_for_ack), + TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid, + wait, no_cck, dont_wait_for_ack), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + CHAN_ENTRY + __field(bool, offchan) + __field(enum nl80211_channel_type, channel_type) + __field(bool, channel_type_valid) + __field(unsigned int, wait) + __field(bool, no_cck) + __field(bool, dont_wait_for_ack) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + CHAN_ASSIGN(chan); + __entry->offchan = offchan; + __entry->channel_type = channel_type; + __entry->channel_type_valid = channel_type_valid; + __entry->wait = wait; + __entry->no_cck = no_cck; + __entry->dont_wait_for_ack = dont_wait_for_ack; + ), + TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, " + "channel type: %d, channel type valid: %s, wait: %u, " + "no cck: %s, dont wait for ack: %s", + WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, + BOOL_TO_STR(__entry->offchan), __entry->channel_type, + BOOL_TO_STR(__entry->channel_type_valid), __entry->wait, + BOOL_TO_STR(__entry->no_cck), + BOOL_TO_STR(__entry->dont_wait_for_ack)) +); + +TRACE_EVENT(rdev_set_noack_map, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u16 noack_map), + TP_ARGS(wiphy, netdev, noack_map), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u16, noack_map) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->noack_map = noack_map; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", noack_map: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) +); + +TRACE_EVENT(rdev_get_et_sset_count, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset), + TP_ARGS(wiphy, netdev, sset), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(int, sset) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->sset = sset; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) +); + +TRACE_EVENT(rdev_get_et_strings, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset), + TP_ARGS(wiphy, netdev, sset), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u32, sset) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->sset = sset; + ), + TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + +TRACE_EVENT(rdev_return_channel, + TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, + enum nl80211_channel_type type), + TP_ARGS(wiphy, chan, type), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + __field(enum nl80211_channel_type, type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(chan); + __entry->type = type; + ), + TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d", + WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type) +); + +#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#include From 4ee3e063f10acf6fd17c0ee6f1d0a95726e74cb2 Mon Sep 17 00:00:00 2001 From: Beni Lev Date: Mon, 27 Aug 2012 12:49:39 +0300 Subject: [PATCH 36/38] cfg80211: add cfg80211 exported function tracing Also add tracing to the API functions that drivers (and mac80211) can call in cfg80211. Signed-off-by: Beni Lev Reviewed-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/wireless/chan.c | 13 +- net/wireless/ibss.c | 2 + net/wireless/mesh.c | 1 + net/wireless/mlme.c | 55 ++++- net/wireless/nl80211.c | 5 + net/wireless/scan.c | 13 + net/wireless/trace.h | 536 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 615 insertions(+), 10 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 71c362587965..48febd2160ba 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -53,6 +53,8 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *sec_chan; int diff; + trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type); + switch (channel_type) { case NL80211_CHAN_HT40PLUS: diff = 20; @@ -61,20 +63,25 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, diff = -20; break; default: + trace_cfg80211_return_bool(true); return true; } sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); - if (!sec_chan) + if (!sec_chan) { + trace_cfg80211_return_bool(false); return false; + } /* we'll need a DFS capability later */ if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_RADAR)) + IEEE80211_CHAN_RADAR)) { + trace_cfg80211_return_bool(false); return false; - + } + trace_cfg80211_return_bool(true); return true; } EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 7fda94fb1a3e..27941d5db72b 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -62,6 +62,8 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) struct cfg80211_event *ev; unsigned long flags; + trace_cfg80211_ibss_joined(dev, bssid); + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); ev = kzalloc(sizeof(*ev), gfp); diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index a18bb3417be5..966cfc4cd79d 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -242,6 +242,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; + trace_cfg80211_notify_new_peer_candidate(dev, macaddr); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) return; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 2a74395e6ab3..46aeafce08d0 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -24,6 +24,7 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_send_rx_auth(dev); wdev_lock(wdev); nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); @@ -44,6 +45,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, u8 *ie = mgmt->u.assoc_resp.variable; int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + trace_cfg80211_send_rx_assoc(dev, bss); wdev_lock(wdev); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); @@ -100,6 +102,7 @@ void __cfg80211_send_deauth(struct net_device *dev, const u8 *bssid = mgmt->bssid; bool was_current = false; + trace___cfg80211_send_deauth(dev); ASSERT_WDEV_LOCK(wdev); if (wdev->current_bss && @@ -149,6 +152,7 @@ void __cfg80211_send_disassoc(struct net_device *dev, u16 reason_code; bool from_ap; + trace___cfg80211_send_disassoc(dev); ASSERT_WDEV_LOCK(wdev); nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); @@ -190,6 +194,7 @@ void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_send_unprot_deauth(dev); nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC); } EXPORT_SYMBOL(cfg80211_send_unprot_deauth); @@ -201,6 +206,7 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_send_unprot_disassoc(dev); nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC); } EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); @@ -211,6 +217,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_send_auth_timeout(dev, addr); wdev_lock(wdev); nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); @@ -229,6 +236,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_send_assoc_timeout(dev, addr); wdev_lock(wdev); nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); @@ -263,6 +271,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, } #endif + trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc); nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); } EXPORT_SYMBOL(cfg80211_michael_mic_failure); @@ -582,6 +591,8 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, + duration); nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, duration, gfp); } @@ -595,6 +606,8 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan, + channel_type); nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, channel_type, gfp); } @@ -606,6 +619,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_new_sta(dev, mac_addr, sinfo); nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); } EXPORT_SYMBOL(cfg80211_new_sta); @@ -615,6 +629,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_del_sta(dev, mac_addr); nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); } EXPORT_SYMBOL(cfg80211_del_sta); @@ -867,10 +882,13 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); u16 stype; + trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm); stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; - if (!(stypes->rx & BIT(stype))) + if (!(stypes->rx & BIT(stype))) { + trace_cfg80211_return_bool(false); return false; + } data = buf + ieee80211_hdrlen(mgmt->frame_control); data_len = len - ieee80211_hdrlen(mgmt->frame_control); @@ -901,6 +919,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, spin_unlock_bh(&wdev->mgmt_registrations_lock); + trace_cfg80211_return_bool(result); return result; } EXPORT_SYMBOL(cfg80211_rx_mgmt); @@ -911,6 +930,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); + /* Indicate TX status of the Action frame to user space */ nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); } @@ -924,6 +945,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_cqm_rssi_notify(dev, rssi_event); + /* Indicate roaming trigger event to user space */ nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); } @@ -936,6 +959,8 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); + /* Indicate roaming trigger event to user space */ nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); } @@ -961,6 +986,7 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_gtk_rekey_notify(dev, bssid); nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); } EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); @@ -972,6 +998,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); } EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); @@ -984,6 +1011,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_channel *chan; + trace_cfg80211_ch_switch_notify(dev, freq, type); + wdev_lock(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && @@ -1006,12 +1035,18 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; + bool ret; + + trace_cfg80211_rx_spurious_frame(dev, addr); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && - wdev->iftype != NL80211_IFTYPE_P2P_GO)) + wdev->iftype != NL80211_IFTYPE_P2P_GO)) { + trace_cfg80211_return_bool(false); return false; - - return nl80211_unexpected_frame(dev, addr, gfp); + } + ret = nl80211_unexpected_frame(dev, addr, gfp); + trace_cfg80211_return_bool(ret); + return ret; } EXPORT_SYMBOL(cfg80211_rx_spurious_frame); @@ -1019,12 +1054,18 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; + bool ret; + + trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO && - wdev->iftype != NL80211_IFTYPE_AP_VLAN)) + wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { + trace_cfg80211_return_bool(false); return false; - - return nl80211_unexpected_4addr_frame(dev, addr, gfp); + } + ret = nl80211_unexpected_4addr_frame(dev, addr, gfp); + trace_cfg80211_return_bool(ret); + return ret; } EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e26f7455538d..5d3167d71b5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8876,7 +8876,10 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, void *hdr; int err; + trace_cfg80211_probe_status(dev, addr, cookie, acked); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) return; @@ -8918,6 +8921,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, void *hdr; u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); + trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); + if (!nlportid) return; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a957077dd961..7f97a087f452 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -145,6 +145,7 @@ void __cfg80211_scan_done(struct work_struct *wk) void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { + trace_cfg80211_scan_done(request, aborted); WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; @@ -182,6 +183,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) void cfg80211_sched_scan_results(struct wiphy *wiphy) { + trace_cfg80211_sched_scan_results(wiphy); /* ignore if we're not scanning */ if (wiphy_to_dev(wiphy)->sched_scan_req) queue_work(cfg80211_wq, @@ -193,6 +195,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + trace_cfg80211_sched_scan_stopped(wiphy); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, true); mutex_unlock(&rdev->sched_scan_mtx); @@ -485,6 +489,9 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct cfg80211_internal_bss *bss, *res = NULL; unsigned long now = jiffies; + trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask, + capa_val); + spin_lock_bh(&dev->bss_lock); list_for_each_entry(bss, &dev->bss_list, list) { @@ -506,6 +513,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, spin_unlock_bh(&dev->bss_lock); if (!res) return NULL; + trace_cfg80211_return_bss(&res->pub); return &res->pub; } EXPORT_SYMBOL(cfg80211_get_bss); @@ -818,6 +826,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, if (res->pub.capability & WLAN_CAPABILITY_ESS) regulatory_hint_found_beacon(wiphy, channel, gfp); + trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ return &res->pub; } @@ -830,10 +839,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, s32 signal, gfp_t gfp) { struct cfg80211_internal_bss *res; + size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); size_t privsz; + trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); + if (WARN_ON(!mgmt)) return NULL; @@ -887,6 +899,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, if (res->pub.capability & WLAN_CAPABILITY_ESS) regulatory_hint_found_beacon(wiphy, channel, gfp); + trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ return &res->pub; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 0940e9103776..857734c4b357 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1741,6 +1741,542 @@ TRACE_EVENT(rdev_return_channel, WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type) ); +/************************************************************* + * cfg80211 exported functions traces * + *************************************************************/ + +TRACE_EVENT(cfg80211_return_bool, + TP_PROTO(bool ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(bool, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("returned %s", BOOL_TO_STR(__entry->ret)) +); + +DECLARE_EVENT_CLASS(cfg80211_netdev_mac_evt, + TP_PROTO(struct net_device *netdev, const u8 *macaddr), + TP_ARGS(netdev, macaddr), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(macaddr) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(macaddr, macaddr); + ), + TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(macaddr)) +); + +DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_notify_new_peer_candidate, + TP_PROTO(struct net_device *netdev, const u8 *macaddr), + TP_ARGS(netdev, macaddr) +); + +DECLARE_EVENT_CLASS(netdev_evt_only, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev), + TP_STRUCT__entry( + NETDEV_ENTRY + ), + TP_fast_assign( + NETDEV_ASSIGN; + ), + TP_printk(NETDEV_PR_FMT , NETDEV_PR_ARG) +); + +DEFINE_EVENT(netdev_evt_only, cfg80211_send_rx_auth, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev) +); + +TRACE_EVENT(cfg80211_send_rx_assoc, + TP_PROTO(struct net_device *netdev, struct cfg80211_bss *bss), + TP_ARGS(netdev, bss), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(bssid) + CHAN_ENTRY + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(bssid, bss->bssid); + CHAN_ASSIGN(bss->channel); + ), + TP_printk(NETDEV_PR_FMT MAC_PR_FMT CHAN_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) +); + +DEFINE_EVENT(netdev_evt_only, __cfg80211_send_deauth, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev) +); + +DEFINE_EVENT(netdev_evt_only, __cfg80211_send_disassoc, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev) +); + +DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_deauth, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev) +); + +DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_disassoc, + TP_PROTO(struct net_device *netdev), + TP_ARGS(netdev) +); + +DECLARE_EVENT_CLASS(netdev_mac_evt, + TP_PROTO(struct net_device *netdev, const u8 *mac), + TP_ARGS(netdev, mac), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(mac) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(mac, mac) + ), + TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(mac)) +); + +DEFINE_EVENT(netdev_mac_evt, cfg80211_send_auth_timeout, + TP_PROTO(struct net_device *netdev, const u8 *mac), + TP_ARGS(netdev, mac) +); + +DEFINE_EVENT(netdev_mac_evt, cfg80211_send_assoc_timeout, + TP_PROTO(struct net_device *netdev, const u8 *mac), + TP_ARGS(netdev, mac) +); + +TRACE_EVENT(cfg80211_michael_mic_failure, + TP_PROTO(struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, const u8 *tsc), + TP_ARGS(netdev, addr, key_type, key_id, tsc), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(addr) + __field(enum nl80211_key_type, key_type) + __field(int, key_id) + __array(u8, tsc, 6) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(addr, addr); + __entry->key_type = key_type; + __entry->key_id = key_id; + memcpy(__entry->tsc, tsc, 6); + ), + TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm", + NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type, + __entry->key_id, __entry->tsc) +); + +TRACE_EVENT(cfg80211_ready_on_channel, + TP_PROTO(struct wireless_dev *wdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, unsigned int duration), + TP_ARGS(wdev, cookie, chan, channel_type, duration), + TP_STRUCT__entry( + WDEV_ENTRY + __field(u64, cookie) + CHAN_ENTRY + __field(enum nl80211_channel_type, channel_type) + __field(unsigned int, duration) + ), + TP_fast_assign( + WDEV_ASSIGN; + __entry->cookie = cookie; + CHAN_ASSIGN(chan); + __entry->channel_type = channel_type; + __entry->duration = duration; + ), + TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u", + WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, + __entry->channel_type, __entry->duration) +); + +TRACE_EVENT(cfg80211_ready_on_channel_expired, + TP_PROTO(struct wireless_dev *wdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type), + TP_ARGS(wdev, cookie, chan, channel_type), + TP_STRUCT__entry( + WDEV_ENTRY + __field(u64, cookie) + CHAN_ENTRY + __field(enum nl80211_channel_type, channel_type) + ), + TP_fast_assign( + WDEV_ASSIGN; + __entry->cookie = cookie; + CHAN_ASSIGN(chan); + __entry->channel_type = channel_type; + ), + TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d", + WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG, + __entry->channel_type) +); + +TRACE_EVENT(cfg80211_new_sta, + TP_PROTO(struct net_device *netdev, const u8 *mac_addr, + struct station_info *sinfo), + TP_ARGS(netdev, mac_addr, sinfo), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(mac_addr) + SINFO_ENTRY + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(mac_addr, mac_addr); + SINFO_ASSIGN; + ), + TP_printk(NETDEV_PR_FMT MAC_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(mac_addr)) +); + +DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_del_sta, + TP_PROTO(struct net_device *netdev, const u8 *macaddr), + TP_ARGS(netdev, macaddr) +); + +TRACE_EVENT(cfg80211_rx_mgmt, + TP_PROTO(struct wireless_dev *wdev, int freq, int sig_mbm), + TP_ARGS(wdev, freq, sig_mbm), + TP_STRUCT__entry( + WDEV_ENTRY + __field(int, freq) + __field(int, sig_mbm) + ), + TP_fast_assign( + WDEV_ASSIGN; + __entry->freq = freq; + __entry->sig_mbm = sig_mbm; + ), + TP_printk(WDEV_PR_FMT ", freq: %d, sig mbm: %d", + WDEV_PR_ARG, __entry->freq, __entry->sig_mbm) +); + +TRACE_EVENT(cfg80211_mgmt_tx_status, + TP_PROTO(struct wireless_dev *wdev, u64 cookie, bool ack), + TP_ARGS(wdev, cookie, ack), + TP_STRUCT__entry( + WDEV_ENTRY + __field(u64, cookie) + __field(bool, ack) + ), + TP_fast_assign( + WDEV_ASSIGN; + __entry->cookie = cookie; + __entry->ack = ack; + ), + TP_printk(WDEV_PR_FMT", cookie: %llu, ack: %s", + WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack)) +); + +TRACE_EVENT(cfg80211_cqm_rssi_notify, + TP_PROTO(struct net_device *netdev, + enum nl80211_cqm_rssi_threshold_event rssi_event), + TP_ARGS(netdev, rssi_event), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(enum nl80211_cqm_rssi_threshold_event, rssi_event) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->rssi_event = rssi_event; + ), + TP_printk(NETDEV_PR_FMT ", rssi event: %d", + NETDEV_PR_ARG, __entry->rssi_event) +); + +TRACE_EVENT(cfg80211_can_beacon_sec_chan, + TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type), + TP_ARGS(wiphy, channel, channel_type), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + __field(enum nl80211_channel_type, channel_type) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(channel); + __entry->channel_type = channel_type; + ), + TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d", + WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type) +); + +TRACE_EVENT(cfg80211_ch_switch_notify, + TP_PROTO(struct net_device *netdev, int freq, + enum nl80211_channel_type type), + TP_ARGS(netdev, freq, type), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(int, freq) + __field(enum nl80211_channel_type, type) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->freq = freq; + __entry->type = type; + ), + TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG, + __entry->freq, __entry->type) +); + +DECLARE_EVENT_CLASS(cfg80211_rx_evt, + TP_PROTO(struct net_device *netdev, const u8 *addr), + TP_ARGS(netdev, addr), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(addr) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(addr, addr); + ), + TP_printk(NETDEV_PR_FMT MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) +); + +DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, + TP_PROTO(struct net_device *netdev, const u8 *addr), + TP_ARGS(netdev, addr) +); + +DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, + TP_PROTO(struct net_device *netdev, const u8 *addr), + TP_ARGS(netdev, addr) +); + +DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame, + TP_PROTO(struct net_device *netdev, const u8 *addr), + TP_ARGS(netdev, addr) +); + +TRACE_EVENT(cfg80211_probe_status, + TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, + bool acked), + TP_ARGS(netdev, addr, cookie, acked), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(addr) + __field(u64, cookie) + __field(bool, acked) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(addr, addr); + __entry->cookie = cookie; + __entry->acked = acked; + ), + TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", cookie: %llu, acked: %s", + NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie, + BOOL_TO_STR(__entry->acked)) +); + +TRACE_EVENT(cfg80211_cqm_pktloss_notify, + TP_PROTO(struct net_device *netdev, const u8 *peer, u32 num_packets), + TP_ARGS(netdev, peer, num_packets), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(u32, num_packets) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->num_packets = num_packets; + ), + TP_printk(NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", num of lost packets: %u", + NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->num_packets) +); + +DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_gtk_rekey_notify, + TP_PROTO(struct net_device *netdev, const u8 *macaddr), + TP_ARGS(netdev, macaddr) +); + +TRACE_EVENT(cfg80211_pmksa_candidate_notify, + TP_PROTO(struct net_device *netdev, int index, const u8 *bssid, + bool preauth), + TP_ARGS(netdev, index, bssid, preauth), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(int, index) + MAC_ENTRY(bssid) + __field(bool, preauth) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->index = index; + MAC_ASSIGN(bssid, bssid); + __entry->preauth = preauth; + ), + TP_printk(NETDEV_PR_FMT ", index:%d, bssid: " MAC_PR_FMT ", pre auth: %s", + NETDEV_PR_ARG, __entry->index, MAC_PR_ARG(bssid), + BOOL_TO_STR(__entry->preauth)) +); + +TRACE_EVENT(cfg80211_report_obss_beacon, + TP_PROTO(struct wiphy *wiphy, const u8 *frame, size_t len, + int freq, int sig_dbm), + TP_ARGS(wiphy, frame, len, freq, sig_dbm), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, freq) + __field(int, sig_dbm) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->freq = freq; + __entry->sig_dbm = sig_dbm; + ), + TP_printk(WIPHY_PR_FMT ", freq: %d, sig_dbm: %d", + WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm) +); + +TRACE_EVENT(cfg80211_scan_done, + TP_PROTO(struct cfg80211_scan_request *request, bool aborted), + TP_ARGS(request, aborted), + TP_STRUCT__entry( + __field(u32, n_channels) + __dynamic_array(u8, ie, request ? request->ie_len : 0) + __array(u32, rates, IEEE80211_NUM_BANDS) + __field(u32, wdev_id) + MAC_ENTRY(wiphy_mac) + __field(bool, no_cck) + __field(bool, aborted) + ), + TP_fast_assign( + if (request) { + memcpy(__get_dynamic_array(ie), request->ie, + request->ie_len); + memcpy(__entry->rates, request->rates, + IEEE80211_NUM_BANDS); + __entry->wdev_id = request->wdev ? + request->wdev->identifier : 0; + if (request->wiphy) + MAC_ASSIGN(wiphy_mac, + request->wiphy->perm_addr); + __entry->no_cck = request->no_cck; + } + __entry->aborted = aborted; + ), + TP_printk("aborted: %s", BOOL_TO_STR(__entry->aborted)) +); + +DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_results, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped, + TP_PROTO(struct wiphy *wiphy), + TP_ARGS(wiphy) +); + +TRACE_EVENT(cfg80211_get_bss, + TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val), + TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + MAC_ENTRY(bssid) + __dynamic_array(u8, ssid, ssid_len) + __field(u16, capa_mask) + __field(u16, capa_val) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(channel); + MAC_ASSIGN(bssid, bssid); + memcpy(__get_dynamic_array(ssid), ssid, ssid_len); + __entry->capa_mask = capa_mask; + __entry->capa_val = capa_val; + ), + TP_printk(WIPHY_PR_FMT CHAN_PR_FMT MAC_PR_FMT ", buf: %#.2x, " + "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, + MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], + __entry->capa_mask, __entry->capa_val) +); + +TRACE_EVENT(cfg80211_inform_bss_frame, + TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, + struct ieee80211_mgmt *mgmt, size_t len, + s32 signal), + TP_ARGS(wiphy, channel, mgmt, len, signal), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_ENTRY + __dynamic_array(u8, mgmt, len) + __field(s32, signal) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_ASSIGN(channel); + if (mgmt) + memcpy(__get_dynamic_array(mgmt), mgmt, len); + __entry->signal = signal; + ), + TP_printk(WIPHY_PR_FMT CHAN_PR_FMT "signal: %d", + WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal) +); + +DECLARE_EVENT_CLASS(cfg80211_bss_evt, + TP_PROTO(struct cfg80211_bss *pub), + TP_ARGS(pub), + TP_STRUCT__entry( + MAC_ENTRY(bssid) + CHAN_ENTRY + ), + TP_fast_assign( + MAC_ASSIGN(bssid, pub->bssid); + CHAN_ASSIGN(pub->channel); + ), + TP_printk(MAC_PR_FMT CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG) +); + +DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss, + TP_PROTO(struct cfg80211_bss *pub), + TP_ARGS(pub) +); + +TRACE_EVENT(cfg80211_return_uint, + TP_PROTO(unsigned int ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(unsigned int, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret: %d", __entry->ret) +); + +TRACE_EVENT(cfg80211_return_u32, + TP_PROTO(u32 ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(u32, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret: %u", __entry->ret) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH From 5c95b940bd97e744267249e3b0780e6ef04b029c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 16 Oct 2012 08:39:22 +0200 Subject: [PATCH 37/38] nl/cfg80211: force scan using an AP vif if requested If the user wants to scan using a vif configured as AP, cfg80211 must give him a chance to do it, even if this will disrupt the stations performance due to off-channel scanning. To do so, this patch adds a 'force' flag to the SCAN_TRIGGER command which tells cfg80211 to perform the scanning operation even if the vif is an AP and the beaconing has already started. Signed-off-by: Antonio Quartulli Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 8 ++++++++ net/mac80211/cfg.c | 11 ++++++++++- net/mac80211/main.c | 4 +++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 0e6277a06c29..617d0fbfc96f 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3050,6 +3050,7 @@ enum nl80211_ap_sme_features { * mode * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported + * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3060,6 +3061,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_SAE = 1 << 5, NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, NL80211_FEATURE_SCAN_FLUSH = 1 << 7, + NL80211_FEATURE_AP_SCAN = 1 << 8, }; /** @@ -3103,10 +3105,16 @@ enum nl80211_connect_failed_reason { * * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning + * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured + * as AP and the beaconing has already been configured. This attribute is + * dangerous because will destroy stations performance as a lot of frames + * will be lost while scanning off-channel, therefore it must be used only + * when really needed */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, NL80211_SCAN_FLAG_FLUSH = 1<<1, + NL80211_SCAN_FLAG_AP = 1<<2, }; #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5739bfbf2999..5eab1325a0f6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1855,7 +1855,16 @@ static int ieee80211_scan(struct wiphy *wiphy, * beaconing hasn't been configured yet */ case NL80211_IFTYPE_AP: - if (sdata->u.ap.beacon) + /* + * If the scan has been forced (and the driver supports + * forcing), don't care about being beaconing already. + * This will create problems to the attached stations (e.g. all + * the frames sent while scanning on other channel will be + * lost) + */ + if (sdata->u.ap.beacon && + (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || + !(req->flags & NL80211_SCAN_FLAG_AP))) return -EOPNOTSUPP; break; default: diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ba5a23249771..c42094be2f0b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -603,7 +603,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NL80211_FEATURE_HT_IBSS; if (!ops->hw_scan) - wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN; + wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | + NL80211_FEATURE_AP_SCAN; + if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; From d012a605108a482392be80710ea35f1db27c4aa9 Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Wed, 10 Oct 2012 12:39:50 -0700 Subject: [PATCH 38/38] mac80211: make client powersave independent of interface type This patch prepares mac80211 for a later implementation of mesh or ad-hoc powersave clients. The structures related to powersave (buffer, TIM map, counters) are moved from the AP-specific interface structure to a generic structure that can be embedded into any interface type. The functions related to powersave are prepared to allow easy extension with different interface types. For example with: + } else if (sta->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { + ps = &sdata->u.mesh.ps; Some references to the AP's beacon structure are removed where they were obviously not used. The patch compiles without warning and has been briefly tested as AP interface with one client in PS mode. Signed-off-by: Marco Porsch Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 6 +- net/mac80211/ieee80211_i.h | 20 ++++--- net/mac80211/iface.c | 6 +- net/mac80211/rx.c | 21 ++++--- net/mac80211/sta_info.c | 43 +++++++++++---- net/mac80211/tx.c | 100 ++++++++++++++++++++-------------- 6 files changed, 122 insertions(+), 74 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8802b8d7be13..3393ad5b8ab1 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -395,14 +395,14 @@ __IEEE80211_IF_FILE_W(uapsd_max_sp_len); /* AP attributes */ IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); -IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); -IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); +IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC); +IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC); static ssize_t ieee80211_if_fmt_num_buffered_multicast( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { return scnprintf(buf, buflen, "%u\n", - skb_queue_len(&sdata->u.ap.ps_bc_buf)); + skb_queue_len(&sdata->u.ap.ps.bc_buf)); } __IEEE80211_IF_FILE(num_buffered_multicast, NULL); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ebc1b5dc4127..3026519b236a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -280,23 +280,27 @@ struct probe_resp { u8 data[0]; }; -struct ieee80211_if_ap { - struct beacon_data __rcu *beacon; - struct probe_resp __rcu *probe_resp; - - struct list_head vlans; - +struct ps_data { /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; - struct sk_buff_head ps_bc_buf; + struct sk_buff_head bc_buf; atomic_t num_sta_ps; /* number of stations in PS mode */ - atomic_t num_mcast_sta; /* number of stations receiving multicast */ int dtim_count; bool dtim_bc_mc; }; +struct ieee80211_if_ap { + struct beacon_data __rcu *beacon; + struct probe_resp __rcu *probe_resp; + + struct list_head vlans; + + struct ps_data ps; + atomic_t num_mcast_sta; /* number of stations receiving multicast */ +}; + struct ieee80211_if_wds { struct sta_info *sta; u8 remote_addr[ETH_ALEN]; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 99f2b19c8f0d..c50cf6b9e28d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -767,8 +767,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, WARN_ON(!list_empty(&sdata->u.ap.vlans)); /* free all potentially still buffered bcast frames */ - local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf); - skb_queue_purge(&sdata->u.ap.ps_bc_buf); + local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); + skb_queue_purge(&sdata->u.ap.ps.bc_buf); } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { ieee80211_mgd_stop(sdata); } @@ -1171,7 +1171,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->vif.p2p = true; /* fall through */ case NL80211_IFTYPE_AP: - skb_queue_head_init(&sdata->u.ap.ps_bc_buf); + skb_queue_head_init(&sdata->u.ap.ps.bc_buf); INIT_LIST_HEAD(&sdata->u.ap.vlans); break; case NL80211_IFTYPE_P2P_CLIENT: diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9f64fc4ecd29..d07216ab5f72 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1141,12 +1141,19 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static void ap_sta_ps_start(struct sta_info *sta) +static void sta_ps_start(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; + struct ps_data *ps; - atomic_inc(&sdata->bss->num_sta_ps); + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || + sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + ps = &sdata->bss->ps; + else + return; + + atomic_inc(&ps->num_sta_ps); set_sta_flag(sta, WLAN_STA_PS_STA); if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); @@ -1154,7 +1161,7 @@ static void ap_sta_ps_start(struct sta_info *sta) sta->sta.addr, sta->sta.aid); } -static void ap_sta_ps_end(struct sta_info *sta) +static void sta_ps_end(struct sta_info *sta) { ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", sta->sta.addr, sta->sta.aid); @@ -1181,9 +1188,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) return -EINVAL; if (start) - ap_sta_ps_start(sta_inf); + sta_ps_start(sta_inf); else - ap_sta_ps_end(sta_inf); + sta_ps_end(sta_inf); return 0; } @@ -1335,10 +1342,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) */ if (ieee80211_is_data(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) - ap_sta_ps_end(sta); + sta_ps_end(sta); } else { if (ieee80211_has_pm(hdr->frame_control)) - ap_sta_ps_start(sta); + sta_ps_start(sta); } } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d5a5d62b6b0c..daf55e1e0fd3 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -98,6 +98,7 @@ static void free_sta_work(struct work_struct *wk) struct tid_ampdu_tx *tid_tx; struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; + struct ps_data *ps; /* * At this point, when being called as call_rcu callback, @@ -107,11 +108,15 @@ static void free_sta_work(struct work_struct *wk) */ if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - BUG_ON(!sdata->bss); + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || + sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + ps = &sdata->bss->ps; + else + return; clear_sta_flag(sta, WLAN_STA_PS_STA); - atomic_dec(&sdata->bss->num_sta_ps); + atomic_dec(&ps->num_sta_ps); sta_info_recalc_tim(sta); } @@ -502,22 +507,22 @@ int sta_info_insert(struct sta_info *sta) return err; } -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) +static inline void __bss_tim_set(u8 *tim, u16 id) { /* * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __set_bit() format. */ - bss->tim[aid / 8] |= (1 << (aid % 8)); + tim[id / 8] |= (1 << (id % 8)); } -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) +static inline void __bss_tim_clear(u8 *tim, u16 id) { /* * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __clear_bit() format. */ - bss->tim[aid / 8] &= ~(1 << (aid % 8)); + tim[id / 8] &= ~(1 << (id % 8)); } static unsigned long ieee80211_tids_for_ac(int ac) @@ -541,14 +546,23 @@ static unsigned long ieee80211_tids_for_ac(int ac) void sta_info_recalc_tim(struct sta_info *sta) { struct ieee80211_local *local = sta->local; - struct ieee80211_if_ap *bss = sta->sdata->bss; + struct ps_data *ps; unsigned long flags; bool indicate_tim = false; u8 ignore_for_tim = sta->sta.uapsd_queues; int ac; + u16 id; + + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || + sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + if (WARN_ON_ONCE(!sta->sdata->bss)) + return; - if (WARN_ON_ONCE(!sta->sdata->bss)) + ps = &sta->sdata->bss->ps; + id = sta->sta.aid; + } else { return; + } /* No need to do anything if the driver does all */ if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) @@ -587,9 +601,9 @@ void sta_info_recalc_tim(struct sta_info *sta) spin_lock_irqsave(&local->tim_lock, flags); if (indicate_tim) - __bss_tim_set(bss, sta->sta.aid); + __bss_tim_set(ps->tim, id); else - __bss_tim_clear(bss, sta->sta.aid); + __bss_tim_clear(ps->tim, id); if (local->ops->set_tim) { local->tim_in_locked_section = true; @@ -948,10 +962,17 @@ static void clear_sta_ps_flags(void *_sta) { struct sta_info *sta = _sta; struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ps_data *ps; + + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + ps = &sdata->bss->ps; + else + return; clear_sta_flag(sta, WLAN_STA_PS_DRIVER); if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) - atomic_dec(&sdata->bss->num_sta_ps); + atomic_dec(&ps->num_sta_ps); } /* powersave support code */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bbe1d86beea1..065f81cb5618 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -325,16 +325,19 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) struct sta_info *sta; list_for_each_entry_rcu(sdata, &local->interfaces, list) { - struct ieee80211_if_ap *ap; - if (sdata->vif.type != NL80211_IFTYPE_AP) + struct ps_data *ps; + + if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->u.ap.ps; + else continue; - ap = &sdata->u.ap; - skb = skb_dequeue(&ap->ps_bc_buf); + + skb = skb_dequeue(&ps->bc_buf); if (skb) { purged++; dev_kfree_skb(skb); } - total += skb_queue_len(&ap->ps_bc_buf); + total += skb_queue_len(&ps->bc_buf); } /* @@ -364,6 +367,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + struct ps_data *ps; /* * broadcast/multicast frame @@ -373,16 +377,24 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) * This is done either by the hardware or us. */ - /* powersaving STAs only in AP/VLAN mode */ - if (!tx->sdata->bss) + /* powersaving STAs currently only in AP/VLAN mode */ + if (tx->sdata->vif.type == NL80211_IFTYPE_AP || + tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + if (!tx->sdata->bss) + return TX_CONTINUE; + + ps = &tx->sdata->bss->ps; + } else { return TX_CONTINUE; + } + /* no buffering for ordered frames */ if (ieee80211_has_order(hdr->frame_control)) return TX_CONTINUE; /* no stations in PS mode */ - if (!atomic_read(&tx->sdata->bss->num_sta_ps)) + if (!atomic_read(&ps->num_sta_ps)) return TX_CONTINUE; info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; @@ -397,14 +409,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); - if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { + if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) { ps_dbg(tx->sdata, "BC TX buffer full - dropping the oldest frame\n"); - dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); + dev_kfree_skb(skb_dequeue(&ps->bc_buf)); } else tx->local->total_ps_buffered++; - skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); + skb_queue_tail(&ps->bc_buf, tx->skb); return TX_QUEUED; } @@ -2246,9 +2258,8 @@ void ieee80211_tx_pending(unsigned long data) /* functions for drivers to get certain frames */ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, - struct ieee80211_if_ap *bss, - struct sk_buff *skb, - struct beacon_data *beacon) + struct ps_data *ps, + struct sk_buff *skb) { u8 *pos, *tim; int aid0 = 0; @@ -2256,27 +2267,27 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ - if (atomic_read(&bss->num_sta_ps) > 0) + if (atomic_read(&ps->num_sta_ps) > 0) /* in the hope that this is faster than * checking byte-for-byte */ - have_bits = !bitmap_empty((unsigned long*)bss->tim, + have_bits = !bitmap_empty((unsigned long*)ps->tim, IEEE80211_MAX_AID+1); - if (bss->dtim_count == 0) - bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1; + if (ps->dtim_count == 0) + ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; else - bss->dtim_count--; + ps->dtim_count--; tim = pos = (u8 *) skb_put(skb, 6); *pos++ = WLAN_EID_TIM; *pos++ = 4; - *pos++ = bss->dtim_count; + *pos++ = ps->dtim_count; *pos++ = sdata->vif.bss_conf.dtim_period; - if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) + if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf)) aid0 = 1; - bss->dtim_bc_mc = aid0 == 1; + ps->dtim_bc_mc = aid0 == 1; if (have_bits) { /* Find largest even number N1 so that bits numbered 1 through @@ -2284,14 +2295,14 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, * (N2 + 1) x 8 through 2007 are 0. */ n1 = 0; for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { - if (bss->tim[i]) { + if (ps->tim[i]) { n1 = i & 0xfe; break; } } n2 = n1; for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { - if (bss->tim[i]) { + if (ps->tim[i]) { n2 = i; break; } @@ -2301,7 +2312,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, *pos++ = n1 | aid0; /* Part Virt Bitmap */ skb_put(skb, n2 - n1); - memcpy(pos, bss->tim + n1, n2 - n1 + 1); + memcpy(pos, ps->tim + n1, n2 - n1 + 1); tim[1] = n2 - n1 + 4; } else { @@ -2318,8 +2329,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct sk_buff *skb = NULL; struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata = NULL; - struct ieee80211_if_ap *ap = NULL; - struct beacon_data *beacon; enum ieee80211_band band; struct ieee80211_tx_rate_control txrc; struct ieee80211_chanctx_conf *chanctx_conf; @@ -2338,8 +2347,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *tim_length = 0; if (sdata->vif.type == NL80211_IFTYPE_AP) { - ap = &sdata->u.ap; - beacon = rcu_dereference(ap->beacon); + struct ieee80211_if_ap *ap = &sdata->u.ap; + struct beacon_data *beacon = rcu_dereference(ap->beacon); + if (beacon) { /* * headroom, head length, @@ -2363,14 +2373,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - ieee80211_beacon_add_tim(sdata, ap, skb, - beacon); + ieee80211_beacon_add_tim(sdata, &ap->ps, skb); } else { unsigned long flags; spin_lock_irqsave(&local->tim_lock, flags); - ieee80211_beacon_add_tim(sdata, ap, skb, - beacon); + ieee80211_beacon_add_tim(sdata, &ap->ps, skb); spin_unlock_irqrestore(&local->tim_lock, flags); } @@ -2694,32 +2702,40 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct sk_buff *skb = NULL; struct ieee80211_tx_data tx; struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_ap *bss = NULL; - struct beacon_data *beacon; + struct ps_data *ps; struct ieee80211_tx_info *info; struct ieee80211_chanctx_conf *chanctx_conf; sdata = vif_to_sdata(vif); - bss = &sdata->u.ap; rcu_read_lock(); - beacon = rcu_dereference(bss->beacon); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head || - !chanctx_conf) + if (!chanctx_conf) + goto out; + + if (sdata->vif.type == NL80211_IFTYPE_AP) { + struct beacon_data *beacon = + rcu_dereference(sdata->u.ap.beacon); + + if (!beacon || !beacon->head) + goto out; + + ps = &sdata->u.ap.ps; + } else { goto out; + } - if (bss->dtim_count != 0 || !bss->dtim_bc_mc) + if (ps->dtim_count != 0 || !ps->dtim_bc_mc) goto out; /* send buffered bc/mc only after DTIM beacon */ while (1) { - skb = skb_dequeue(&bss->ps_bc_buf); + skb = skb_dequeue(&ps->bc_buf); if (!skb) goto out; local->total_ps_buffered--; - if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { + if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* more buffered multicast/broadcast frames ==> set