summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-07-26 10:01:25 -0700
committerDavid S. Miller <davem@davemloft.net>2009-07-26 10:01:25 -0700
commitc8b201ff867e64b6233d069563081775269f4499 (patch)
tree35d363e6cb565fd7285480dc877a2da79eafb9a7 /net/mac80211
parent436b355b96042ab6564f43a7dabd5c61d9634ff7 (diff)
parent249b405cf8145da8a74b70544ae1079d244bdb00 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig12
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/agg-tx.c3
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/driver-ops.h85
-rw-r--r--net/mac80211/driver-trace.c6
-rw-r--r--net/mac80211/driver-trace.h648
-rw-r--r--net/mac80211/ibss.c9
-rw-r--r--net/mac80211/ieee80211_i.h47
-rw-r--r--net/mac80211/iface.c51
-rw-r--r--net/mac80211/main.c120
-rw-r--r--net/mac80211/mesh.c5
-rw-r--r--net/mac80211/mesh_hwmp.c9
-rw-r--r--net/mac80211/mesh_pathtbl.c26
-rw-r--r--net/mac80211/mlme.c308
-rw-r--r--net/mac80211/rate.c31
-rw-r--r--net/mac80211/rc80211_minstrel.c23
-rw-r--r--net/mac80211/rc80211_pid_algo.c12
-rw-r--r--net/mac80211/rx.c55
-rw-r--r--net/mac80211/scan.c19
-rw-r--r--net/mac80211/tx.c323
-rw-r--r--net/mac80211/util.c68
-rw-r--r--net/mac80211/wep.c6
-rw-r--r--net/mac80211/wep.h3
-rw-r--r--net/mac80211/wme.c6
-rw-r--r--net/mac80211/wme.h3
27 files changed, 1330 insertions, 555 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 182c9c5c681..19a4c66e143 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -206,3 +206,15 @@ config MAC80211_DEBUG_COUNTERS
and show them in debugfs.
If unsure, say N.
+
+config MAC80211_DRIVER_API_TRACER
+ bool "Driver API tracer"
+ depends on MAC80211_DEBUG_MENU
+ depends on EVENT_TRACING
+ help
+ Say Y here to make mac80211 register with the ftrace
+ framework for the driver API -- you can see which
+ driver methods it is calling then by looking at the
+ trace.
+
+ If unsure, say N.
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 0e3ab88bb70..91284a74ff9 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -41,6 +41,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
mac80211-$(CONFIG_PM) += pm.o
+mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
+CFLAGS_driver-trace.o := -I$(src)
+
# objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 9e5762ad307..1958c7c42cd 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- /* mark queue as pending, it is stopped already */
- __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
- &local->queue_stop_reasons[queue]);
/* copy over remaining packets */
skb_queue_splice_tail_init(
&sta->ampdu_mlme.tid_tx[tid]->pending,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 36f8f245fa4..52928ad9057 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1293,7 +1293,7 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy)
}
#ifdef CONFIG_NL80211_TESTMODE
-int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 6c439cd5cce..96991b68f04 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
for (q = 0; q < local->hw.queues; q++)
res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
local->queue_stop_reasons[q],
- __netif_subqueue_stopped(local->mdev, q));
+ skb_queue_len(&local->pending[q]));
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b13446afd48..4100c361a99 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -3,6 +3,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
+#include "driver-trace.h"
static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
{
@@ -11,29 +12,37 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
static inline int drv_start(struct ieee80211_local *local)
{
- return local->ops->start(&local->hw);
+ int ret = local->ops->start(&local->hw);
+ trace_drv_start(local, ret);
+ return ret;
}
static inline void drv_stop(struct ieee80211_local *local)
{
local->ops->stop(&local->hw);
+ trace_drv_stop(local);
}
static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
{
- return local->ops->add_interface(&local->hw, conf);
+ int ret = local->ops->add_interface(&local->hw, conf);
+ trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
+ return ret;
}
static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
{
local->ops->remove_interface(&local->hw, conf);
+ trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
}
static inline int drv_config(struct ieee80211_local *local, u32 changed)
{
- return local->ops->config(&local->hw, changed);
+ int ret = local->ops->config(&local->hw, changed);
+ trace_drv_config(local, changed, ret);
+ return ret;
}
static inline void drv_bss_info_changed(struct ieee80211_local *local,
@@ -43,6 +52,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
{
if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, vif, info, changed);
+ trace_drv_bss_info_changed(local, vif, info, changed);
}
static inline void drv_configure_filter(struct ieee80211_local *local,
@@ -53,14 +63,18 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
{
local->ops->configure_filter(&local->hw, changed_flags, total_flags,
mc_count, mc_list);
+ trace_drv_configure_filter(local, changed_flags, total_flags,
+ mc_count);
}
static inline int drv_set_tim(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool set)
{
+ int ret = 0;
if (local->ops->set_tim)
- return local->ops->set_tim(&local->hw, sta, set);
- return 0;
+ ret = local->ops->set_tim(&local->hw, sta, set);
+ trace_drv_set_tim(local, sta, set, ret);
+ return ret;
}
static inline int drv_set_key(struct ieee80211_local *local,
@@ -68,7 +82,9 @@ static inline int drv_set_key(struct ieee80211_local *local,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- return local->ops->set_key(&local->hw, cmd, vif, sta, key);
+ int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
+ trace_drv_set_key(local, cmd, vif, sta, key, ret);
+ return ret;
}
static inline void drv_update_tkip_key(struct ieee80211_local *local,
@@ -79,32 +95,41 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, conf, address,
iv32, phase1key);
+ trace_drv_update_tkip_key(local, conf, address, iv32);
}
static inline int drv_hw_scan(struct ieee80211_local *local,
struct cfg80211_scan_request *req)
{
- return local->ops->hw_scan(&local->hw, req);
+ int ret = local->ops->hw_scan(&local->hw, req);
+ trace_drv_hw_scan(local, req, ret);
+ return ret;
}
static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
if (local->ops->sw_scan_start)
local->ops->sw_scan_start(&local->hw);
+ trace_drv_sw_scan_start(local);
}
static inline void drv_sw_scan_complete(struct ieee80211_local *local)
{
if (local->ops->sw_scan_complete)
local->ops->sw_scan_complete(&local->hw);
+ trace_drv_sw_scan_complete(local);
}
static inline int drv_get_stats(struct ieee80211_local *local,
struct ieee80211_low_level_stats *stats)
{
- if (!local->ops->get_stats)
- return -EOPNOTSUPP;
- return local->ops->get_stats(&local->hw, stats);
+ int ret = -EOPNOTSUPP;
+
+ if (local->ops->get_stats)
+ ret = local->ops->get_stats(&local->hw, stats);
+ trace_drv_get_stats(local, stats, ret);
+
+ return ret;
}
static inline void drv_get_tkip_seq(struct ieee80211_local *local,
@@ -112,14 +137,17 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local,
{
if (local->ops->get_tkip_seq)
local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
+ trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
}
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
u32 value)
{
+ int ret = 0;
if (local->ops->set_rts_threshold)
- return local->ops->set_rts_threshold(&local->hw, value);
- return 0;
+ ret = local->ops->set_rts_threshold(&local->hw, value);
+ trace_drv_set_rts_threshold(local, value, ret);
+ return ret;
}
static inline void drv_sta_notify(struct ieee80211_local *local,
@@ -129,46 +157,57 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
{
if (local->ops->sta_notify)
local->ops->sta_notify(&local->hw, vif, cmd, sta);
+ trace_drv_sta_notify(local, vif, cmd, sta);
}
static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
+ int ret = -EOPNOTSUPP;
if (local->ops->conf_tx)
- return local->ops->conf_tx(&local->hw, queue, params);
- return -EOPNOTSUPP;
+ ret = local->ops->conf_tx(&local->hw, queue, params);
+ trace_drv_conf_tx(local, queue, params, ret);
+ return ret;
}
static inline int drv_get_tx_stats(struct ieee80211_local *local,
struct ieee80211_tx_queue_stats *stats)
{
- return local->ops->get_tx_stats(&local->hw, stats);
+ int ret = local->ops->get_tx_stats(&local->hw, stats);
+ trace_drv_get_tx_stats(local, stats, ret);
+ return ret;
}
static inline u64 drv_get_tsf(struct ieee80211_local *local)
{
+ u64 ret = -1ULL;
if (local->ops->get_tsf)
- return local->ops->get_tsf(&local->hw);
- return -1ULL;
+ ret = local->ops->get_tsf(&local->hw);
+ trace_drv_get_tsf(local, ret);
+ return ret;
}
static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
{
if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, tsf);
+ trace_drv_set_tsf(local, tsf);
}
static inline void drv_reset_tsf(struct ieee80211_local *local)
{
if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw);
+ trace_drv_reset_tsf(local);
}
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
{
+ int ret = 1;
if (local->ops->tx_last_beacon)
- return local->ops->tx_last_beacon(&local->hw);
- return 1;
+ ret = local->ops->tx_last_beacon(&local->hw);
+ trace_drv_tx_last_beacon(local, ret);
+ return ret;
}
static inline int drv_ampdu_action(struct ieee80211_local *local,
@@ -176,10 +215,12 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
struct ieee80211_sta *sta, u16 tid,
u16 *ssn)
{
+ int ret = -EOPNOTSUPP;
if (local->ops->ampdu_action)
- return local->ops->ampdu_action(&local->hw, action,
- sta, tid, ssn);
- return -EOPNOTSUPP;
+ ret = local->ops->ampdu_action(&local->hw, action,
+ sta, tid, ssn);
+ trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
+ return ret;
}
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
new file mode 100644
index 00000000000..6da6f79932f
--- /dev/null
+++ b/net/mac80211/driver-trace.c
@@ -0,0 +1,6 @@
+/* bug in tracepoint.h, it should include this */
+#include <linux/module.h>
+
+#include "driver-ops.h"
+#define CREATE_TRACE_POINTS
+#include "driver-trace.h"
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
new file mode 100644
index 00000000000..5a10da2d70f
--- /dev/null
+++ b/net/mac80211/driver-trace.h
@@ -0,0 +1,648 @@
+#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __MAC80211_DRIVER_TRACE
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211
+
+#define MAXNAME 32
+#define LOCAL_ENTRY __array(char, wiphy_name, 32)
+#define LOCAL_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
+#define LOCAL_PR_FMT "%s"
+#define LOCAL_PR_ARG __entry->wiphy_name
+
+#define STA_ENTRY __array(char, sta_addr, ETH_ALEN)
+#define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
+#define STA_PR_FMT " sta:%pM"
+#define STA_PR_ARG __entry->sta_addr
+
+#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif)
+#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
+#define VIF_PR_FMT " vif:%p(%d)"
+#define VIF_PR_ARG __entry->vif, __entry->vif_type
+
+TRACE_EVENT(drv_start,
+ TP_PROTO(struct ieee80211_local *local, int ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_stop,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_add_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ const u8 *addr,
+ struct ieee80211_vif *vif,
+ int ret),
+
+ TP_ARGS(local, addr, vif, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, addr, 6)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->addr, addr, 6);
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_remove_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ const u8 *addr, struct ieee80211_vif *vif),
+
+ TP_ARGS(local, addr, vif),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, addr, 6)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->addr, addr, 6);
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+ )
+);
+
+TRACE_EVENT(drv_config,
+ TP_PROTO(struct ieee80211_local *local,
+ u32 changed,
+ int ret),
+
+ TP_ARGS(local, changed, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, changed)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->changed = changed;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ch:%#x ret:%d",
+ LOCAL_PR_ARG, __entry->changed, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_bss_info_changed,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed),
+
+ TP_ARGS(local, vif, info, changed),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(bool, assoc)
+ __field(u16, aid)
+ __field(bool, cts)
+ __field(bool, shortpre)
+ __field(bool, shortslot)
+ __field(u8, dtimper)
+ __field(u16, bcnint)
+ __field(u16, assoc_cap)
+ __field(u64, timestamp)
+ __field(u32, basic_rates)
+ __field(u32, changed)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->changed = changed;
+ __entry->aid = info->aid;
+ __entry->assoc = info->assoc;
+ __entry->shortpre = info->use_short_preamble;
+ __entry->cts = info->use_cts_prot;
+ __entry->shortslot = info->use_short_slot;
+ __entry->dtimper = info->dtim_period;
+ __entry->bcnint = info->beacon_int;
+ __entry->assoc_cap = info->assoc_capability;
+ __entry->timestamp = info->timestamp;
+ __entry->basic_rates = info->basic_rates;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " changed:%#x",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
+ )
+);
+
+TRACE_EVENT(drv_configure_filter,
+ TP_PROTO(struct ieee80211_local *local,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count),
+
+ TP_ARGS(local, changed_flags, total_flags, mc_count),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(unsigned int, changed)
+ __field(unsigned int, total)
+ __field(int, mc)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->changed = changed_flags;
+ __entry->total = *total_flags;
+ __entry->mc = mc_count;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " changed:%#x total:%#x mc:%d",
+ LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc
+ )
+);
+
+TRACE_EVENT(drv_set_tim,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta, bool set, int ret),
+
+ TP_ARGS(local, sta, set, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ __field(bool, set)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ __entry->set = set;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d",
+ LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_set_key,
+ TP_PROTO(struct ieee80211_local *local,
+ enum set_key_cmd cmd, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key, int ret),
+
+ TP_ARGS(local, cmd, vif, sta, key, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(enum ieee80211_key_alg, alg)
+ __field(u8, hw_key_idx)
+ __field(u8, flags)
+ __field(s8, keyidx)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->alg = key->alg;
+ __entry->flags = key->flags;
+ __entry->keyidx = key->keyidx;
+ __entry->hw_key_idx = key->hw_key_idx;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_update_tkip_key,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_key_conf *conf,
+ const u8 *address, u32 iv32),
+
+ TP_ARGS(local, conf, address, iv32),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __array(u8, addr, 6)
+ __field(u32, iv32)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ memcpy(__entry->addr, address, 6);
+ __entry->iv32 = iv32;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " addr:%pM iv32:%#x",
+ LOCAL_PR_ARG, __entry->addr, __entry->iv32
+ )
+);
+
+TRACE_EVENT(drv_hw_scan,
+ TP_PROTO(struct ieee80211_local *local,
+ struct cfg80211_scan_request *req, int ret),
+
+ TP_ARGS(local, req, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_sw_scan_start,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_sw_scan_complete,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_get_stats,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_low_level_stats *stats,
+ int ret),
+
+ TP_ARGS(local, stats, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ __field(unsigned int, ackfail)
+ __field(unsigned int, rtsfail)
+ __field(unsigned int, fcserr)
+ __field(unsigned int, rtssucc)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ __entry->ackfail = stats->dot11ACKFailureCount;
+ __entry->rtsfail = stats->dot11RTSFailureCount;
+ __entry->fcserr = stats->dot11FCSErrorCount;
+ __entry->rtssucc = stats->dot11RTSSuccessCount;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tkip_seq,
+ TP_PROTO(struct ieee80211_local *local,
+ u8 hw_key_idx, u32 *iv32, u16 *iv16),
+
+ TP_ARGS(local, hw_key_idx, iv32, iv16),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u8, hw_key_idx)
+ __field(u32, iv32)
+ __field(u16, iv16)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->hw_key_idx = hw_key_idx;
+ __entry->iv32 = *iv32;
+ __entry->iv16 = *iv16;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_set_rts_threshold,
+ TP_PROTO(struct ieee80211_local *local, u32 value, int ret),
+
+ TP_ARGS(local, value, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, value)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ __entry->value = value;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " value:%d ret:%d",
+ LOCAL_PR_ARG, __entry->value, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_sta_notify,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta),
+
+ TP_ARGS(local, vif, cmd, sta),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(u32, cmd)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " cmd:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
+ )
+);
+
+TRACE_EVENT(drv_conf_tx,
+ TP_PROTO(struct ieee80211_local *local, u16 queue,
+ const struct ieee80211_tx_queue_params *params,
+ int ret),
+
+ TP_ARGS(local, queue, params, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u16, queue)
+ __field(u16, txop)
+ __field(u16, cw_min)
+ __field(u16, cw_max)
+ __field(u8, aifs)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->queue = queue;
+ __entry->ret = ret;
+ __entry->txop = params->txop;
+ __entry->cw_max = params->cw_max;
+ __entry->cw_min = params->cw_min;
+ __entry->aifs = params->aifs;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " queue:%d ret:%d",
+ LOCAL_PR_ARG, __entry->queue, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tx_stats,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_tx_queue_stats *stats,
+ int ret),
+
+ TP_ARGS(local, stats, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tsf,
+ TP_PROTO(struct ieee80211_local *local, u64 ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u64, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%llu",
+ LOCAL_PR_ARG, (unsigned long long)__entry->ret
+ )
+);
+
+TRACE_EVENT(drv_set_tsf,
+ TP_PROTO(struct ieee80211_local *local, u64 tsf),
+
+ TP_ARGS(local, tsf),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u64, tsf)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->tsf = tsf;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " tsf:%llu",
+ LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+ )
+);
+
+TRACE_EVENT(drv_reset_tsf,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_tx_last_beacon,
+ TP_PROTO(struct ieee80211_local *local, int ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_ampdu_action,
+ TP_PROTO(struct ieee80211_local *local,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid,
+ u16 *ssn, int ret),
+
+ TP_ARGS(local, action, sta, tid, ssn, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ __field(u32, action)
+ __field(u16, tid)
+ __field(u16, ssn)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ __entry->ret = ret;
+ __entry->action = action;
+ __entry->tid = tid;
+ __entry->ssn = *ssn;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
+ LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+ )
+);
+#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE driver-trace
+#include <trace/define_trace.h>
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 15d5a53b59a..8e2220000e5 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
*/
if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
- sdata->u.ibss.bssid, 0);
+ sdata->u.ibss.bssid, NULL, 0, 0);
}
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key)
+ if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
else
sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
return;
capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key)
+ if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
-
if (ifibss->fixed_bssid)
bssid = ifibss->bssid;
if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
} else
sdata->u.ibss.fixed_bssid = false;
+ sdata->u.ibss.privacy = params->privacy;
+
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
sdata->u.ibss.channel = params->channel;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 327aabc07ab..6a0177137dd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -247,18 +247,22 @@ struct ieee80211_mgd_work {
int tries;
+ u8 key[WLAN_KEY_LEN_WEP104];
+ u8 key_len, key_idx;
+
/* must be last */
u8 ie[0]; /* for auth or assoc frame, not probe */
};
/* flags used in struct ieee80211_if_managed.flags */
enum ieee80211_sta_flags {
- IEEE80211_STA_PROBEREQ_POLL = BIT(3),
- IEEE80211_STA_CONTROL_PORT = BIT(4),
- IEEE80211_STA_WMM_ENABLED = BIT(5),
- IEEE80211_STA_DISABLE_11N = BIT(6),
- IEEE80211_STA_CSA_RECEIVED = BIT(7),
- IEEE80211_STA_MFP_ENABLED = BIT(8),
+ IEEE80211_STA_BEACON_POLL = BIT(0),
+ IEEE80211_STA_CONNECTION_POLL = BIT(1),
+ IEEE80211_STA_CONTROL_PORT = BIT(2),
+ IEEE80211_STA_WMM_ENABLED = BIT(3),
+ IEEE80211_STA_DISABLE_11N = BIT(4),
+ IEEE80211_STA_CSA_RECEIVED = BIT(5),
+ IEEE80211_STA_MFP_ENABLED = BIT(6),
};
/* flags for MLME request */
@@ -268,11 +272,16 @@ enum ieee80211_sta_request {
struct ieee80211_if_managed {
struct timer_list timer;
+ struct timer_list conn_mon_timer;
+ struct timer_list bcn_mon_timer;
struct timer_list chswitch_timer;
struct work_struct work;
+ struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_loss_work;
+ unsigned long probe_timeout;
+
struct mutex mtx;
struct ieee80211_bss *associated;
struct list_head work_list;
@@ -289,8 +298,6 @@ struct ieee80211_if_managed {
unsigned long request;
- unsigned long last_beacon;
-
unsigned int flags;
u32 beacon_crc;
@@ -321,6 +328,7 @@ struct ieee80211_if_ibss {
bool fixed_bssid;
bool fixed_channel;
+ bool privacy;
u8 bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -559,14 +567,9 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_CSA,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
- IEEE80211_QUEUE_STOP_REASON_PENDING,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
};
-struct ieee80211_master_priv {
- struct ieee80211_local *local;
-};
-
struct ieee80211_local {
/* embed the driver visible part.
* don't cast (use the static inlines below), but we keep
@@ -579,13 +582,20 @@ struct ieee80211_local {
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
- struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
+
+ /* protects the aggregated multicast list and filter calls */
+ spinlock_t filter_lock;
+
+ /* aggregated multicast list */
+ struct dev_addr_list *mc_list;
+ int mc_count;
+
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
/*
@@ -805,10 +815,6 @@ struct ieee80211_local {
static inline struct ieee80211_sub_if_data *
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- BUG_ON(!local || local->mdev == dev);
-
return netdev_priv(dev);
}
@@ -988,7 +994,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
void ieee80211_tx_pending(unsigned long data);
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -1093,8 +1098,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
- u8 *extra, size_t extra_len,
- const u8 *bssid, int encrypt);
+ u8 *extra, size_t extra_len, const u8 *bssid,
+ const u8 *key, u8 key_len, u8 key_idx);
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len);
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 4839a2d97a3..2f797a86ced 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev)
ETH_ALEN);
}
- if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
- memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
- ETH_ALEN);
-
/*
* Validate the MAC address for this device.
*/
@@ -229,9 +225,9 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
break;
default:
conf.vif = &sdata->vif;
@@ -243,9 +239,9 @@ static int ieee80211_open(struct net_device *dev)
if (ieee80211_vif_is_mesh(&sdata->vif)) {
local->fif_other_bss++;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
ieee80211_start_mesh(sdata);
}
@@ -279,10 +275,6 @@ static int ieee80211_open(struct net_device *dev)
}
if (local->open_count == 0) {
- res = dev_open(local->mdev);
- WARN_ON(res);
- if (res)
- goto err_del_interface;
tasklet_enable(&local->tx_pending_tasklet);
tasklet_enable(&local->tasklet);
}
@@ -393,7 +385,14 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_dec(&local->iff_promiscs);
- dev_mc_unsync(local->mdev, dev);
+ netif_addr_lock_bh(dev);
+ spin_lock_bh(&local->filter_lock);
+ __dev_addr_unsync(&local->mc_list, &local->mc_count,
+ &dev->mc_list, &dev->mc_count);
+ ieee80211_configure_filter(local);
+ spin_unlock_bh(&local->filter_lock);
+ netif_addr_unlock_bh(dev);
+
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -442,23 +441,25 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
break;
case NL80211_IFTYPE_STATION:
del_timer_sync(&sdata->u.mgd.chswitch_timer);
del_timer_sync(&sdata->u.mgd.timer);
+ del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+ del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
/*
- * If the timer fired while we waited for it, it will have
- * requeued the work. Now the work will be running again
+ * If any of the timers fired while we waited for it, it will
+ * have queued its work. Now the work will be running again
* but will not rearm the timer again because it checks
* whether the interface is running, which, at this point,
* it no longer is.
*/
cancel_work_sync(&sdata->u.mgd.work);
cancel_work_sync(&sdata->u.mgd.chswitch_work);
-
+ cancel_work_sync(&sdata->u.mgd.monitor_work);
cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
/*
@@ -485,9 +486,9 @@ static int ieee80211_stop(struct net_device *dev)
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
ieee80211_stop_mesh(sdata);
}
@@ -533,9 +534,6 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
- if (netif_running(local->mdev))
- dev_close(local->mdev);
-
drv_stop(local);
ieee80211_led_radio(local, false);
@@ -582,8 +580,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
-
- dev_mc_sync(local->mdev, dev);
+ spin_lock_bh(&local->filter_lock);
+ __dev_addr_sync(&local->mc_list, &local->mc_count,
+ &dev->mc_list, &dev->mc_count);
+ ieee80211_configure_filter(local);
+ spin_unlock_bh(&local->filter_lock);
}
/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5b69f5f0729..3234f3751d2 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
new_flags |= (1<<31);
drv_configure_filter(local, changed_flags, &new_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
+ local->mc_count,
+ local->mc_list);
WARN_ON(new_flags & (1<<31));
local->filter_flags = new_flags & ~(1<<31);
}
-/* master interface */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
-static const struct header_ops ieee80211_header_ops = {
- .create = eth_header,
- .parse = header_parse_80211,
- .rebuild = eth_rebuild_header,
- .cache = eth_header_cache,
- .cache_update = eth_header_cache_update,
-};
-
-static int ieee80211_master_open(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
- struct ieee80211_sub_if_data *sdata;
- int res = -EOPNOTSUPP;
-
- /* we hold the RTNL here so can safely walk the list */
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (netif_running(sdata->dev)) {
- res = 0;
- break;
- }
- }
-
- if (res)
- return res;
-
- netif_tx_start_all_queues(local->mdev);
-
- return 0;
-}
-
-static int ieee80211_master_stop(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
- struct ieee80211_sub_if_data *sdata;
-
- /* we hold the RTNL here so can safely walk the list */
- list_for_each_entry(sdata, &local->interfaces, list)
- if (netif_running(sdata->dev))
- dev_close(sdata->dev);
-
- return 0;
-}
-
-static void ieee80211_master_set_multicast_list(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
-
- ieee80211_configure_filter(local);
-}
-
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
struct ieee80211_channel *chan, *scan_chan;
@@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
- skb->dev = local->mdev;
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
@@ -716,7 +654,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
mutex_init(&local->scan_mtx);
spin_lock_init(&local->key_lock);
-
+ spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
@@ -752,30 +690,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
-static const struct net_device_ops ieee80211_master_ops = {
- .ndo_start_xmit = ieee80211_master_start_xmit,
- .ndo_open = ieee80211_master_open,
- .ndo_stop = ieee80211_master_stop,
- .ndo_set_multicast_list = ieee80211_master_set_multicast_list,
- .ndo_select_queue = ieee80211_select_queue,
-};
-
-static void ieee80211_master_setup(struct net_device *mdev)
-{
- mdev->type = ARPHRD_IEEE80211;
- mdev->netdev_ops = &ieee80211_master_ops;
- mdev->header_ops = &ieee80211_header_ops;
- mdev->tx_queue_len = 1000;
- mdev->addr_len = ETH_ALEN;
-}
-
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
int result;
enum ieee80211_band band;
- struct net_device *mdev;
- struct ieee80211_master_priv *mpriv;
int channels, i, j, max_bitrates;
bool supp_ht;
static const u32 cipher_suites[] = {
@@ -874,16 +793,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
- mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
- "wmaster%d", ieee80211_master_setup,
- hw->queues);
- if (!mdev)
- goto fail_mdev_alloc;
-
- mpriv = netdev_priv(mdev);
- mpriv->local = local;
- local->mdev = mdev;
-
local->hw.workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
@@ -918,17 +827,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
rtnl_lock();
- result = dev_alloc_name(local->mdev, local->mdev->name);
- if (result < 0)
- goto fail_dev;
-
- memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
- SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
- local->mdev->features |= NETIF_F_NETNS_LOCAL;
-
- result = register_netdevice(local->mdev);
- if (result < 0)
- goto fail_dev;
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
@@ -981,9 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
fail_rate:
- unregister_netdevice(local->mdev);
- local->mdev = NULL;
- fail_dev:
rtnl_unlock();
ieee80211_wep_free(local);
fail_wep:
@@ -992,9 +887,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- if (local->mdev)
- free_netdev(local->mdev);
- fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
kfree(local->int_scan_req.channels);
@@ -1019,13 +911,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
-
- /* First, we remove all virtual interfaces. */
ieee80211_remove_interfaces(local);
- /* then, finally, remove the master interface */
- unregister_netdevice(local->mdev);
-
rtnl_unlock();
ieee80211_clear_tx_pending(local);
@@ -1044,7 +931,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- free_netdev(local->mdev);
kfree(local->int_scan_req.channels);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 542ea025494..8a97b142308 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -685,9 +685,12 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
fc = le16_to_cpu(mgmt->frame_control);
switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ if (skb->len < IEEE80211_MIN_ACTION_SIZE)
+ return RX_DROP_MONITOR;
+ /* fall through */
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_ACTION:
skb_queue_tail(&ifmsh->skb_queue, skb);
queue_work(local->hw.workqueue, &ifmsh->work);
return RX_QUEUED;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f49ef288e2e..e93c37ef6a4 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -686,11 +686,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
u8 ttl, dst_flags;
u32 lifetime;
- spin_lock(&ifmsh->mesh_preq_queue_lock);
+ spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
if (!ifmsh->preq_queue_len ||
time_before(jiffies, ifmsh->last_preq +
min_preq_int_jiff(sdata))) {
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
return;
}
@@ -698,7 +698,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
struct mesh_preq_queue, list);
list_del(&preq_node->list);
--ifmsh->preq_queue_len;
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
rcu_read_lock();
mpath = mesh_path_lookup(preq_node->dst, sdata);
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
mesh_path_add(dst_addr, sdata);
mpath = mesh_path_lookup(dst_addr, sdata);
if (!mpath) {
- dev_kfree_skb(skb);
sdata->u.mesh.mshstats.dropped_frames_no_route++;
err = -ENOSPC;
goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
memcpy(hdr->addr1, mpath->next_hop->sta.addr,
ETH_ALEN);
} else {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!(mpath->flags & MESH_PATH_RESOLVING)) {
/* Start discovery only if it is not running yet */
mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
skb_unlink(skb_to_free, &mpath->frame_queue);
}
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&mpath->frame_queue, skb);
if (skb_to_free)
mesh_path_discard_frame(skb_to_free, sdata);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 479597e8858..04b9e4d61b8 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -55,7 +55,25 @@ static DEFINE_RWLOCK(pathtbl_resize_lock);
*/
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff_head tmpq;
+ unsigned long flags;
+
rcu_assign_pointer(mpath->next_hop, sta);
+
+ __skb_queue_head_init(&tmpq);
+
+ spin_lock_irqsave(&mpath->frame_queue.lock, flags);
+
+ while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+ __skb_queue_tail(&tmpq, skb);
+ }
+
+ skb_queue_splice(&tmpq, &mpath->frame_queue);
+ spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}
@@ -481,11 +499,9 @@ enddel:
*/
void mesh_path_tx_pending(struct mesh_path *mpath)
{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&mpath->frame_queue)) &&
- (mpath->flags & MESH_PATH_ACTIVE))
- dev_queue_xmit(skb);
+ if (mpath->flags & MESH_PATH_ACTIVE)
+ ieee80211_add_pending_skbs(mpath->sdata->local,
+ &mpath->frame_queue);
}
/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c9db9646025..523c0d994d1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -31,8 +31,23 @@
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_WAIT (HZ / 5)
+
+/*
+ * beacon loss detection timeout
+ * XXX: should depend on beacon interval
+ */
+#define IEEE80211_BEACON_LOSS_TIME (2 * HZ)
+/*
+ * Time the connection can be idle before we probe
+ * it to see if we can still talk to the AP.
+ */
+#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ)
+/*
+ * Time we wait for a probe response after sending
+ * a probe request because of beacon loss or for
+ * checking the connection still works.
+ */
+#define IEEE80211_PROBE_WAIT (HZ / 5)
#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1
@@ -72,6 +87,35 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
WARN_ON(!mutex_is_locked(&ifmgd->mtx));
}
+/*
+ * We can have multiple work items (and connection probing)
+ * scheduling this timer, but we need to take care to only
+ * reschedule it when it should fire _earlier_ than it was
+ * asked for before, or if it's not pending right now. This
+ * function ensures that. Note that it then is required to
+ * run this function for all timeouts after the first one
+ * has happened -- the work that runs from this timer will
+ * do that.
+ */
+static void run_again(struct ieee80211_if_managed *ifmgd,
+ unsigned long timeout)
+{
+ ASSERT_MGD_MTX(ifmgd);
+
+ if (!timer_pending(&ifmgd->timer) ||
+ time_before(timeout, ifmgd->timer.expires))
+ mod_timer(&ifmgd->timer, timeout);
+}
+
+static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER)
+ return;
+
+ mod_timer(&sdata->u.mgd.bcn_mon_timer,
+ round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
+}
+
static int ecw2cw(int ecw)
{
return (1 << ecw) - 1;
@@ -646,7 +690,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
if (count == 1 && found->u.mgd.powersave &&
found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
- !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
+ !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))) {
s32 beaconint_us;
if (latency < 0)
@@ -852,6 +897,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.associated = bss;
memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
+ /* just to be sure */
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
+
ieee80211_led_assoc(local, 1);
sdata->vif.bss_conf.assoc = 1;
@@ -916,7 +965,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
- mod_timer(&ifmgd->timer, wk->timeout);
+ run_again(ifmgd, wk->timeout);
return RX_MGMT_NONE;
}
@@ -954,25 +1003,30 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
- wk->bss->cbss.bssid, 0);
+ wk->bss->cbss.bssid, NULL, 0, 0);
wk->auth_transaction = 2;
wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
- mod_timer(&ifmgd->timer, wk->timeout);
+ run_again(ifmgd, wk->timeout);
return RX_MGMT_NONE;
}
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
- const u8 *bssid, bool deauth)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0, config_changed = 0;
+ u8 bssid[ETH_ALEN];
ASSERT_MGD_MTX(ifmgd);
+ if (WARN_ON(!ifmgd->associated))
+ return;
+
+ memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+
ifmgd->associated = NULL;
memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -1079,7 +1133,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
ieee80211_send_assoc(sdata, wk);
wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
- mod_timer(&ifmgd->timer, wk->timeout);
+ run_again(ifmgd, wk->timeout);
return RX_MGMT_NONE;
}
@@ -1092,31 +1146,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
* from AP because we know that the connection is working both ways
* at that time. But multicast frames (and hence also beacons) must
* be ignored here, because we need to trigger the timer during
- * data idle periods for sending the periodical probe request to
- * the AP.
+ * data idle periods for sending the periodic probe request to the
+ * AP we're connected to.
*/
- if (!is_multicast_ether_addr(hdr->addr1))
- mod_timer(&sdata->u.mgd.timer,
- jiffies + IEEE80211_MONITORING_INTERVAL);
+ if (is_multicast_ether_addr(hdr->addr1))
+ return;
+
+ mod_timer(&sdata->u.mgd.conn_mon_timer,
+ round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
}
-void ieee80211_beacon_loss_work(struct work_struct *work)
+static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
+ bool beacon)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data,
- u.mgd.beacon_loss_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
const u8 *ssid;
+ bool already = false;
- /*
- * The driver has already reported this event and we have
- * already sent a probe request. Maybe the AP died and the
- * driver keeps reporting until we disassociate... We have
- * to ignore that because otherwise we would continually
- * reset the timer and never check whether we received a
- * probe response!
- */
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+ if (!netif_running(sdata->dev))
return;
mutex_lock(&ifmgd->mtx);
@@ -1125,12 +1172,35 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
goto out;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: driver reports beacon loss from AP "
+ if (beacon && net_ratelimit())
+ printk(KERN_DEBUG "%s: detected beacon loss from AP "
"- sending probe request\n", sdata->dev->name);
#endif
- ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ /*
+ * The driver/our work has already reported this event or the
+ * connection monitoring has kicked in and we have already sent
+ * a probe request. Or maybe the AP died and the driver keeps
+ * reporting until we disassociate...
+ *
+ * In either case we have to ignore the current call to this
+ * function (except for setting the correct probe reason bit)
+ * because otherwise we would reset the timer every time and
+ * never check whether we received a probe response!
+ */
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ already = true;
+
+ if (beacon)
+ ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
+ else
+ ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
+
+ if (already)
+ goto out;
+
+ ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1);
@@ -1140,11 +1210,21 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
ssid + 2, ssid[1], NULL, 0);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
+ run_again(ifmgd, ifmgd->probe_timeout);
+
out:
mutex_unlock(&ifmgd->mtx);
}
+void ieee80211_beacon_loss_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.beacon_loss_work);
+
+ ieee80211_mgd_probe_ap(sdata, true);
+}
+
void ieee80211_beacon_loss(struct ieee80211_vif *vif)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -1176,7 +1256,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
return;
ieee80211_send_auth(sdata, 3, wk->auth_alg,
elems.challenge - 2, elems.challenge_len + 2,
- wk->bss->cbss.bssid, 1);
+ wk->bss->cbss.bssid,
+ wk->key, wk->key_len, wk->key_idx);
wk->auth_transaction = 4;
}
@@ -1257,7 +1338,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
sdata->dev->name, bssid, reason_code);
if (!wk) {
- ieee80211_set_disassoc(sdata, bssid, true);
+ ieee80211_set_disassoc(sdata);
} else {
list_del(&wk->list);
kfree(wk);
@@ -1290,7 +1371,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
sdata->dev->name, reason_code);
- ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false);
+ ieee80211_set_disassoc(sdata);
return RX_MGMT_CFG80211_DISASSOC;
}
@@ -1349,8 +1430,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
sdata->dev->name, tu, ms);
wk->timeout = jiffies + msecs_to_jiffies(ms);
if (ms > IEEE80211_ASSOC_TIMEOUT)
- mod_timer(&ifmgd->timer,
- jiffies + msecs_to_jiffies(ms));
+ run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
return RX_MGMT_NONE;
}
@@ -1392,9 +1472,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
return RX_MGMT_NONE;
}
- /* update new sta with its last rx activity */
- sta->last_rx = jiffies;
-
set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_AP);
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -1497,10 +1574,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_set_associated(sdata, wk->bss, changed);
/*
- * initialise the time of last beacon to be the association time,
- * otherwise beacon loss check will trigger immediately
+ * Start timer to probe the connection to the AP now.
+ * Also start the timer that will detect beacon loss.
*/
- ifmgd->last_beacon = jiffies;
+ ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
+ mod_beacon_timer(sdata);
list_del(&wk->list);
kfree(wk);
@@ -1584,11 +1662,22 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated &&
memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
- ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL)) {
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1);
mutex_unlock(&sdata->local->iflist_mtx);
+ /*
+ * We've received a probe response, but are not sure whether
+ * we have or will be receiving any beacons or data, so let's
+ * schedule the timers again, just in case.
+ */
+ mod_beacon_timer(sdata);
+ mod_timer(&ifmgd->conn_mon_timer,
+ round_jiffies_up(jiffies +
+ IEEE80211_CONNECTION_IDLE_TIME));
}
}
@@ -1638,27 +1727,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (rx_status->freq != local->hw.conf.channel->center_freq)
return;
- if (WARN_ON(!ifmgd->associated))
+ /*
+ * We might have received a number of frames, among them a
+ * disassoc frame and a beacon...
+ */
+ if (!ifmgd->associated)
return;
bssid = ifmgd->associated->cbss.bssid;
- if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0))
+ /*
+ * And in theory even frames from a different AP we were just
+ * associated to a split-second ago!
+ */
+ if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+ if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: cancelling probereq poll due "
"to a received beacon\n", sdata->dev->name);
}
#endif
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
}
+ /*
+ * Push the beacon loss detection into the future since
+ * we are processing a beacon from the AP just now.
+ */
+ mod_beacon_timer(sdata);
+
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
len - baselen, &elems,
@@ -1960,6 +2063,37 @@ static void ieee80211_sta_work(struct work_struct *work)
/* then process the rest of the work */
mutex_lock(&ifmgd->mtx);
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL) &&
+ ifmgd->associated) {
+ if (time_is_after_jiffies(ifmgd->probe_timeout))
+ run_again(ifmgd, ifmgd->probe_timeout);
+ else {
+ u8 bssid[ETH_ALEN];
+ /*
+ * We actually lost the connection ... or did we?
+ * Let's make sure!
+ */
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
+ memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+ printk(KERN_DEBUG "No probe response from AP %pM"
+ " after %dms, disconnecting.\n",
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
+ ieee80211_set_disassoc(sdata);
+ mutex_unlock(&ifmgd->mtx);
+ /*
+ * must be outside lock due to cfg80211,
+ * but that's not a problem.
+ */
+ ieee80211_send_deauth_disassoc(sdata, bssid,
+ IEEE80211_STYPE_DEAUTH,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ NULL);
+ mutex_lock(&ifmgd->mtx);
+ }
+ }
+
list_for_each_entry(wk, &ifmgd->work_list, list) {
if (wk->state != IEEE80211_MGD_STATE_IDLE) {
anybusy = true;
@@ -1980,8 +2114,15 @@ static void ieee80211_sta_work(struct work_struct *work)
}
list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
- if (time_before(jiffies, wk->timeout))
+ if (time_is_after_jiffies(wk->timeout)) {
+ /*
+ * This work item isn't supposed to be worked on
+ * right now, but take care to adjust the timer
+ * properly.
+ */
+ run_again(ifmgd, wk->timeout);
continue;
+ }
switch (wk->state) {
default:
@@ -2040,15 +2181,54 @@ static void ieee80211_sta_work(struct work_struct *work)
ieee80211_recalc_idle(local);
}
+static void ieee80211_sta_bcn_mon_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_local *local = sdata->local;
+
+ if (local->quiescing)
+ return;
+
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.mgd.beacon_loss_work);
+}
+
+static void ieee80211_sta_conn_mon_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_local *local = sdata->local;
+
+ if (local->quiescing)
+ return;
+
+ queue_work(local->hw.workqueue, &ifmgd->monitor_work);
+}
+
+static void ieee80211_sta_monitor_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.monitor_work);
+
+ if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+ return;
+
+ ieee80211_mgd_probe_ap(sdata, false);
+}
+
static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- /*
- * Need to update last_beacon to avoid beacon loss
- * test to trigger.
- */
- sdata->u.mgd.last_beacon = jiffies;
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL);
+ /* let's probe the connection once */
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.mgd.monitor_work);
+ /* and do all the other regular work too */
queue_work(sdata->local->hw.workqueue,
&sdata->u.mgd.work);
}
@@ -2073,6 +2253,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->chswitch_work);
if (del_timer_sync(&ifmgd->chswitch_timer))
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+
+ cancel_work_sync(&ifmgd->monitor_work);
+ /* these will just be re-established on connection */
+ del_timer_sync(&ifmgd->conn_mon_timer);
+ del_timer_sync(&ifmgd->bcn_mon_timer);
}
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
@@ -2093,10 +2278,15 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->work, ieee80211_sta_work);
+ INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
+ setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
+ (unsigned long) sdata);
+ setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer,
+ (unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
(unsigned long) sdata);
skb_queue_head_init(&ifmgd->skb_queue);
@@ -2175,6 +2365,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
wk->ie_len = req->ie_len;
}
+ if (req->key && req->key_len) {
+ wk->key_len = req->key_len;
+ wk->key_idx = req->key_idx;
+ memcpy(wk->key, req->key, req->key_len);
+ }
+
ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
memcpy(wk->ssid, ssid + 2, ssid[1]);
wk->ssid_len = ssid[1];
@@ -2290,7 +2486,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
bssid = req->bss->bssid;
- ieee80211_set_disassoc(sdata, bssid, true);
+ ieee80211_set_disassoc(sdata);
} else list_for_each_entry(wk, &ifmgd->work_list, list) {
if (&wk->bss->cbss == req->bss) {
bssid = req->bss->bssid;
@@ -2332,7 +2528,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return -ENOLINK;
}
- ieee80211_set_disassoc(sdata, req->bss->bssid, false);
+ ieee80211_set_disassoc(sdata);
mutex_unlock(&ifmgd->mtx);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 4641f00a1e5..b33efc4fc26 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -198,6 +198,35 @@ static void rate_control_release(struct kref *kref)
kfree(ctrl_ref);
}
+static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
+{
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
+}
+
+bool rate_control_send_low(struct ieee80211_sta *sta,
+ void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+
+ if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
+ info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+ info->control.rates[0].count =
+ (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+ 1 : txrc->hw->max_rate_tries;
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL(rate_control_send_low);
+
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_tx_rate_control *txrc)
@@ -258,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
struct rate_control_ref *ref, *old;
ASSERT_RTNL();
- if (local->open_count || netif_running(local->mdev))
+ if (local->open_count)
return -EBUSY;
ref = rate_control_alloc(name, local);
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 37771abd8f5..7c5142988bb 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -70,20 +70,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
return i;
}
-static inline bool
-use_low_rate(struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u16 fc;
-
- fc = le16_to_cpu(hdr->frame_control);
-
- return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
- (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA);
-}
-
-
static void
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
{
@@ -232,7 +218,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
void *priv_sta, struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
- struct ieee80211_supported_band *sband = txrc->sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct minstrel_sta_info *mi = priv_sta;
struct minstrel_priv *mp = priv;
@@ -245,14 +230,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
int mrr_ndx[3];
int sample_rate;
- if (!sta || !mi || use_low_rate(skb)) {
- ar[0].idx = rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- ar[0].count = 1;
- else
- ar[0].count = mp->max_retry;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a0bef767ceb..8c053be9dc2 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -276,11 +276,9 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
{
struct sk_buff *skb = txrc->skb;
struct ieee80211_supported_band *sband = txrc->sband;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rc_pid_sta_info *spinfo = priv_sta;
int rateidx;
- u16 fc;
if (txrc->rts)
info->control.rates[0].count =
@@ -290,16 +288,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
txrc->hw->conf.short_frame_max_tx_count;
/* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if (!sta || !spinfo ||
- (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK) {
- info->control.rates[0].idx = rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
-
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rateidx = spinfo->txrate_idx;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fe6b9905953..66c797cc85c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -833,28 +833,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (!sta)
return RX_CONTINUE;
- /* Update last_rx only for IBSS packets which are for the current
- * BSSID to avoid keeping the current IBSS network alive in cases where
- * other STAs are using different BSSID. */
+ /*
+ * Update last_rx only for IBSS packets which are for the current
+ * BSSID to avoid keeping the current IBSS network alive in cases
+ * where other STAs start using different BSSID.
+ */
if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
NL80211_IFTYPE_ADHOC);
if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
sta->last_rx = jiffies;
- } else
- if (!is_multicast_ether_addr(hdr->addr1) ||
- rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
- /* Update last_rx only for unicast frames in order to prevent
- * the Probe Request frames (the only broadcast frames from a
- * STA in infrastructure mode) from keeping a connection alive.
+ } else if (!is_multicast_ether_addr(hdr->addr1)) {
+ /*
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
*/
- if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
- ieee80211_is_beacon(hdr->frame_control)) {
- rx->sdata->u.mgd.last_beacon = jiffies;
- } else
- sta->last_rx = jiffies;
+ sta->last_rx = jiffies;
}
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1484,10 +1478,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct ieee80211s_hdr *mesh_hdr;
unsigned int hdrlen;
struct sk_buff *skb = rx->skb, *fwd_skb;
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_sub_if_data *sdata;
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+ sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
if (!ieee80211_is_data(hdr->frame_control))
return RX_CONTINUE;
@@ -1497,10 +1494,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
- struct ieee80211_sub_if_data *sdata;
struct mesh_path *mppath;
- sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
rcu_read_lock();
mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
if (!mppath) {
@@ -1526,6 +1521,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
dropped_frames_ttl);
else {
struct ieee80211_hdr *fwd_hdr;
+ struct ieee80211_tx_info *info;
+
fwd_skb = skb_copy(skb, GFP_ATOMIC);
if (!fwd_skb && net_ratelimit())
@@ -1539,9 +1536,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
*/
memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
- fwd_skb->dev = rx->local->mdev;
+ info = IEEE80211_SKB_CB(fwd_skb);
+ memset(info, 0, sizeof(*info));
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
fwd_skb->iif = rx->dev->ifindex;
- dev_queue_xmit(fwd_skb);
+ ieee80211_select_queue(local, fwd_skb);
+ if (is_multicast_ether_addr(fwd_hdr->addr3))
+ memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+ ETH_ALEN);
+ else {
+ int err = mesh_nexthop_lookup(fwd_skb, sdata);
+ /* Failed to immediately resolve next hop:
+ * fwded frame was dropped or will be added
+ * later to the pending skb queue. */
+ if (err)
+ return RX_DROP_MONITOR;
+ }
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+ fwded_frames);
+ ieee80211_add_pending_skb(local, fwd_skb);
}
}
@@ -1809,8 +1822,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
}
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
- struct ieee80211_hdr *hdr,
+static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
struct ieee80211_rx_data *rx)
{
int keyidx;
@@ -2120,7 +2132,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
- ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+ ieee80211_rx_michael_mic_report(hdr, &rx);
return;
}
@@ -2489,7 +2501,6 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
- skb->dev = local->mdev;
skb->pkt_type = IEEE80211_RX_MSG;
skb_queue_tail(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 5f4f7869d05..74820656dc8 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -294,16 +294,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (was_hw_scan)
goto done;
- netif_tx_lock_bh(local->mdev);
- netif_addr_lock(local->mdev);
+ spin_lock_bh(&local->filter_lock);
local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
-
- netif_addr_unlock(local->mdev);
- netif_tx_unlock_bh(local->mdev);
+ local->mc_count,
+ local->mc_list);
+ spin_unlock_bh(&local->filter_lock);
drv_sw_scan_complete(local);
@@ -382,13 +379,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
local->scan_state = SCAN_SET_CHANNEL;
local->scan_channel_idx = 0;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
- netif_addr_unlock_bh(local->mdev);
+ local->mc_count,
+ local->mc_list);
+ spin_unlock_bh(&local->filter_lock);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
queue_delayed_work(local->hw.workqueue, &local->scan_work,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 60ae086995b..2572509d556 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -451,7 +451,7 @@ ieee80211_tx_h_select_key(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;
- if (unlikely(tx->skb->do_not_encrypt))
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
@@ -497,7 +497,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- tx->skb->do_not_encrypt = 1;
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
return TX_CONTINUE;
}
@@ -512,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
int i, len;
bool inval = false, rts = false, short_preamble = false;
struct ieee80211_tx_rate_control txrc;
+ u32 sta_flags;
memset(&txrc, 0, sizeof(txrc));
@@ -544,7 +545,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
(tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
txrc.short_preamble = short_preamble = true;
+ sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+
+ /*
+ * Lets not bother rate control if we're associated and cannot
+ * talk to the sta. This should not happen.
+ */
+ if (WARN((tx->local->sw_scanning) &&
+ (sta_flags & WLAN_STA_ASSOC) &&
+ !rate_usable_index_exists(sband, &tx->sta->sta),
+ "%s: Dropped data frame as no usable bitrate found while "
+ "scanning and associated. Target station: "
+ "%pM on %d GHz band\n",
+ tx->dev->name, hdr->addr1,
+ tx->channel->band ? 5 : 2))
+ return TX_DROP;
+ /*
+ * If we're associated with the sta at this point we know we can at
+ * least send the frame at the lowest bit rate.
+ */
rate_control_get_rate(tx->sdata, tx->sta, &txrc);
if (unlikely(info->control.rates[0].idx < 0))
@@ -754,9 +774,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
skb_copy_queue_mapping(tmp, skb);
tmp->priority = skb->priority;
- tmp->do_not_encrypt = skb->do_not_encrypt;
tmp->dev = skb->dev;
- tmp->iif = skb->iif;
/* copy header and data */
memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
@@ -784,7 +802,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
/*
* Warn when submitting a fragmented A-MPDU frame and drop it.
- * This scenario is handled in __ieee80211_tx_prepare but extra
+ * This scenario is handled in ieee80211_tx_prepare but extra
* caution taken here as fragmented ampdu may cause Tx stop.
*/
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
@@ -923,11 +941,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
sband = tx->local->hw.wiphy->bands[tx->channel->band];
- skb->do_not_encrypt = 1;
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -965,7 +984,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
skb_trim(skb, skb->len - FCS_LEN);
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- tx->skb->do_not_encrypt = 0;
+ info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
@@ -998,13 +1017,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
* initialises @tx
*/
static ieee80211_tx_result
-__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
- struct sk_buff *skb,
- struct net_device *dev)
+ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_tx_data *tx,
+ struct sk_buff *skb)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
- struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen, tid;
u8 *qc, *state;
@@ -1012,9 +1030,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
- tx->dev = dev; /* use original interface */
+ tx->dev = sdata->dev; /* use original interface */
tx->local = local;
- tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ tx->sdata = sdata;
tx->channel = local->hw.conf.channel;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
@@ -1023,7 +1041,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
tx->flags |= IEEE80211_TX_FRAGMENTED;
/* process and remove the injection radiotap header */
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
if (!__ieee80211_parse_tx_radiotap(tx, skb))
return TX_DROP;
@@ -1119,50 +1136,28 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
return TX_CONTINUE;
}
-/*
- * NB: @tx is uninitialised when passed in here
- */
-static int ieee80211_tx_prepare(struct ieee80211_local *local,
- struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
-{
- struct net_device *dev;
-
- dev = dev_get_by_index(&init_net, skb->iif);
- if (unlikely(dev && !is_ieee80211_device(local, dev))) {
- dev_put(dev);
- dev = NULL;
- }
- if (unlikely(!dev))
- return -ENODEV;
- /*
- * initialises tx with control
- *
- * return value is safe to ignore here because this function
- * can only be invoked for multicast frames
- *
- * XXX: clean up
- */
- __ieee80211_tx_prepare(tx, skb, dev);
- dev_put(dev);
- return 0;
-}
-
static int __ieee80211_tx(struct ieee80211_local *local,
struct sk_buff **skbp,
- struct sta_info *sta)
+ struct sta_info *sta,
+ bool txpending)
{
struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info;
+ unsigned long flags;
int ret, len;
bool fragm = false;
- local->mdev->trans_start = jiffies;
-
while (skb) {
- if (ieee80211_queue_stopped(&local->hw,
- skb_get_queue_mapping(skb)))
- return IEEE80211_TX_PENDING;
+ int q = skb_get_queue_mapping(skb);
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ ret = IEEE80211_TX_OK;
+ if (local->queue_stop_reasons[q] ||
+ (!txpending && !skb_queue_empty(&local->pending[q])))
+ ret = IEEE80211_TX_PENDING;
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ if (ret != IEEE80211_TX_OK)
+ return ret;
info = IEEE80211_SKB_CB(skb);
@@ -1234,10 +1229,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
return 0;
}
-static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
- bool txpending)
+static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, bool txpending)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1248,8 +1243,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
queue = skb_get_queue_mapping(skb);
- WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue]));
-
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
return;
@@ -1258,7 +1251,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
rcu_read_lock();
/* initialises tx */
- res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
+ res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
if (unlikely(res_prepare == TX_DROP)) {
dev_kfree_skb(skb);
@@ -1277,7 +1270,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
retries = 0;
retry:
- ret = __ieee80211_tx(local, &tx.skb, tx.sta);
+ ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
switch (ret) {
case IEEE80211_TX_OK:
break;
@@ -1295,34 +1288,35 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- if (__netif_subqueue_stopped(local->mdev, queue)) {
+ if (local->queue_stop_reasons[queue] ||
+ !skb_queue_empty(&local->pending[queue])) {
+ /*
+ * if queue is stopped, queue up frames for later
+ * transmission from the tasklet
+ */
do {
next = skb->next;
skb->next = NULL;
if (unlikely(txpending))
- skb_queue_head(&local->pending[queue],
- skb);
+ __skb_queue_head(&local->pending[queue],
+ skb);
else
- skb_queue_tail(&local->pending[queue],
- skb);
+ __skb_queue_tail(&local->pending[queue],
+ skb);
} while ((skb = next));
- /*
- * Make sure nobody will enable the queue on us
- * (without going through the tasklet) nor disable the
- * netdev queue underneath the pending handling code.
- */
- __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
- &local->queue_stop_reasons[queue]);
-
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
} else {
+ /*
+ * otherwise retry, but this is a race condition or
+ * a driver bug (which we warn about if it persists)
+ */
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
retries++;
- if (WARN(retries > 10, "tx refused but queue active"))
+ if (WARN(retries > 10, "tx refused but queue active\n"))
goto drop;
goto retry;
}
@@ -1383,14 +1377,13 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
return 0;
}
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct net_device *odev = NULL;
- struct ieee80211_sub_if_data *osdata;
+ struct ieee80211_sub_if_data *tmp_sdata;
int headroom;
bool may_encrypt;
enum {
@@ -1399,20 +1392,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
UNKNOWN_ADDRESS,
} monitor_iface = NOT_MONITOR;
- if (skb->iif)
- odev = dev_get_by_index(&init_net, skb->iif);
- if (unlikely(odev && !is_ieee80211_device(local, odev))) {
- dev_put(odev);
- odev = NULL;
- }
- if (unlikely(!odev)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
- "originating device\n", dev->name);
-#endif
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
+ dev_hold(sdata->dev);
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0 &&
@@ -1428,26 +1408,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
- memset(info, 0, sizeof(*info));
-
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
- osdata = IEEE80211_DEV_TO_SUB_IF(odev);
-
- if (ieee80211_vif_is_mesh(&osdata->vif) &&
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
ieee80211_is_data(hdr->frame_control)) {
if (is_multicast_ether_addr(hdr->addr3))
memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
else
- if (mesh_nexthop_lookup(skb, osdata)) {
- dev_put(odev);
- return NETDEV_TX_OK;
+ if (mesh_nexthop_lookup(skb, sdata)) {
+ dev_put(sdata->dev);
+ return;
}
- if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
- IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
- fwded_frames);
- } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
- struct ieee80211_sub_if_data *sdata;
+ } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
int hdrlen;
u16 len_rthdr;
@@ -1471,19 +1443,17 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces,
+ list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
list) {
- if (!netif_running(sdata->dev))
+ if (!netif_running(tmp_sdata->dev))
continue;
- if (sdata->vif.type != NL80211_IFTYPE_AP)
+ if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
continue;
- if (compare_ether_addr(sdata->dev->dev_addr,
+ if (compare_ether_addr(tmp_sdata->dev->dev_addr,
hdr->addr2)) {
- dev_hold(sdata->dev);
- dev_put(odev);
- osdata = sdata;
- odev = osdata->dev;
- skb->iif = sdata->dev->ifindex;
+ dev_hold(tmp_sdata->dev);
+ dev_put(sdata->dev);
+ sdata = tmp_sdata;
monitor_iface = FOUND_SDATA;
break;
}
@@ -1492,31 +1462,31 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- may_encrypt = !skb->do_not_encrypt;
+ may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
- headroom = osdata->local->tx_headroom;
+ headroom = local->tx_headroom;
if (may_encrypt)
headroom += IEEE80211_ENCRYPT_HEADROOM;
headroom -= skb_headroom(skb);
headroom = max_t(int, 0, headroom);
- if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+ if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
dev_kfree_skb(skb);
- dev_put(odev);
- return NETDEV_TX_OK;
+ dev_put(sdata->dev);
+ return;
}
- if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- osdata = container_of(osdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
+ tmp_sdata = sdata;
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ tmp_sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
if (likely(monitor_iface != UNKNOWN_ADDRESS))
- info->control.vif = &osdata->vif;
-
- ieee80211_tx(odev, skb, false);
- dev_put(odev);
+ info->control.vif = &tmp_sdata->vif;
- return NETDEV_TX_OK;
+ ieee80211_select_queue(local, skb);
+ ieee80211_tx(sdata, skb, false);
+ dev_put(sdata->dev);
}
int ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1526,6 +1496,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct ieee80211_channel *chan = local->hw.conf.channel;
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 len_rthdr;
/*
@@ -1563,15 +1534,9 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (unlikely(skb->len < len_rthdr))
goto fail; /* skb too short for claimed rt header extent */
- skb->dev = local->mdev;
-
/* needed because we set skb device to master */
skb->iif = dev->ifindex;
- /* sometimes we do encrypt injected frames, will be fixed
- * up in radiotap parser if not wanted */
- skb->do_not_encrypt = 0;
-
/*
* fix up the pointers accounting for the radiotap
* header still being in there. We are being given
@@ -1586,8 +1551,10 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
skb_set_network_header(skb, len_rthdr);
skb_set_transport_header(skb, len_rthdr);
- /* pass the radiotap header up to the next stage intact */
- dev_queue_xmit(skb);
+ memset(info, 0, sizeof(*info));
+
+ /* pass the radiotap header up to xmit */
+ ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
return NETDEV_TX_OK;
fail:
@@ -1615,6 +1582,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = NETDEV_TX_BUSY, head_need;
u16 ethertype, hdrlen, meshhdrlen = 0;
__le16 fc;
@@ -1844,7 +1812,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
skb->iif = dev->ifindex;
- skb->dev = local->mdev;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -1855,8 +1822,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
skb_set_network_header(skb, nh_pos);
skb_set_transport_header(skb, h_pos);
+ memset(info, 0, sizeof(*info));
+
dev->trans_start = jiffies;
- dev_queue_xmit(skb);
+ ieee80211_xmit(sdata, skb);
return NETDEV_TX_OK;
@@ -1898,7 +1867,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
return true;
}
- /* validate info->control.vif against skb->iif */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -1912,12 +1880,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
}
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
- ieee80211_tx(dev, skb, true);
+ /* do not use sdata, it may have been changed above */
+ ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
} else {
hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(local, hdr->addr1);
- ret = __ieee80211_tx(local, &skb, sta);
+ ret = __ieee80211_tx(local, &skb, sta, true);
if (ret != IEEE80211_TX_OK)
result = false;
}
@@ -1929,59 +1898,43 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
}
/*
- * Transmit all pending packets. Called from tasklet, locks master device
- * TX lock so that no new packets can come in.
+ * Transmit all pending packets. Called from tasklet.
*/
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
- struct net_device *dev = local->mdev;
unsigned long flags;
int i;
- bool next;
+ bool txok;
rcu_read_lock();
- netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < local->hw.queues; i++) {
/*
* If queue is stopped by something other than due to pending
* frames, or we have no pending frames, proceed to next queue.
*/
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- next = false;
- if (local->queue_stop_reasons[i] !=
- BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) ||
+ if (local->queue_stop_reasons[i] ||
skb_queue_empty(&local->pending[i]))
- next = true;
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- if (next)
continue;
- /*
- * start the queue now to allow processing our packets,
- * we're under the tx lock here anyway so nothing will
- * happen as a result of this
- */
- netif_start_subqueue(local->mdev, i);
-
while (!skb_queue_empty(&local->pending[i])) {
- struct sk_buff *skb = skb_dequeue(&local->pending[i]);
-
- if (!ieee80211_tx_pending_skb(local, skb)) {
- skb_queue_head(&local->pending[i], skb);
+ struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+ flags);
+
+ txok = ieee80211_tx_pending_skb(local, skb);
+ if (!txok)
+ __skb_queue_head(&local->pending[i], skb);
+ spin_lock_irqsave(&local->queue_stop_reason_lock,
+ flags);
+ if (!txok)
break;
- }
}
-
- /* Start regular packet processing again. */
- if (skb_queue_empty(&local->pending[i]))
- ieee80211_wake_queue_by_reason(&local->hw, i,
- IEEE80211_QUEUE_STOP_REASON_PENDING);
}
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- netif_tx_unlock_bh(dev);
rcu_read_unlock();
}
@@ -2156,8 +2109,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
- skb->do_not_encrypt = 1;
-
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
info->band = band;
/*
* XXX: For now, always use the lowest rate
@@ -2228,9 +2180,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
sdata = vif_to_sdata(vif);
bss = &sdata->u.ap;
- if (!bss)
- return NULL;
-
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
@@ -2256,7 +2205,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
- if (!ieee80211_tx_prepare(local, &tx, skb))
+ if (!ieee80211_tx_prepare(sdata, &tx, skb))
break;
dev_kfree_skb_any(skb);
}
@@ -2276,3 +2225,25 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
return skb;
}
EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+ int encrypt)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ skb_set_mac_header(skb, 0);
+ skb_set_network_header(skb, 0);
+ skb_set_transport_header(skb, 0);
+
+ skb->iif = sdata->dev->ifindex;
+ if (!encrypt)
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ /*
+ * The other path calling ieee80211_xmit is from the tasklet,
+ * and while we can handle concurrent transmissions locking
+ * requirements are that we do not come into tx with bhs on.
+ */
+ local_bh_disable();
+ ieee80211_xmit(sdata, skb);
+ local_bh_enable();
+}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 915e7776931..7fc55846d60 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -31,6 +31,7 @@
#include "mesh.h"
#include "wme.h"
#include "led.h"
+#include "wep.h"
/* privid for wiphys to determine whether they belong to us or not */
void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -274,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
__clear_bit(reason, &local->queue_stop_reasons[queue]);
- if (!skb_queue_empty(&local->pending[queue]) &&
- local->queue_stop_reasons[queue] ==
- BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
- tasklet_schedule(&local->tx_pending_tasklet);
-
if (local->queue_stop_reasons[queue] != 0)
/* someone still has this queue stopped */
return;
- netif_wake_subqueue(local->mdev, queue);
+ if (!skb_queue_empty(&local->pending[queue]))
+ tasklet_schedule(&local->tx_pending_tasklet);
}
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -312,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (WARN_ON(queue >= hw->queues))
return;
- /*
- * Only stop if it was previously running, this is necessary
- * for correct pending packets handling because there we may
- * start (but not wake) the queue and rely on that.
- */
- if (!local->queue_stop_reasons[queue])
- netif_stop_subqueue(local->mdev, queue);
-
__set_bit(reason, &local->queue_stop_reasons[queue]);
}
@@ -350,8 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
- __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
- skb_queue_tail(&local->pending[queue], skb);
+ __skb_queue_tail(&local->pending[queue], skb);
__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
@@ -372,16 +360,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
while ((skb = skb_dequeue(skbs))) {
ret++;
queue = skb_get_queue_mapping(skb);
- skb_queue_tail(&local->pending[queue], skb);
+ __skb_queue_tail(&local->pending[queue], skb);
}
- for (i = 0; i < hw->queues; i++) {
- if (ret)
- __ieee80211_stop_queue(hw, i,
- IEEE80211_QUEUE_STOP_REASON_PENDING);
+ for (i = 0; i < hw->queues; i++)
__ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
- }
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return ret;
@@ -412,11 +396,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
+ unsigned long flags;
+ int ret;
if (WARN_ON(queue >= hw->queues))
return true;
- return __netif_subqueue_stopped(local->mdev, queue);
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ ret = !!local->queue_stop_reasons[queue];
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(ieee80211_queue_stopped);
@@ -760,20 +749,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
ieee80211_set_wmm_default(sdata);
}
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- int encrypt)
-{
- skb->dev = sdata->local->mdev;
- skb_set_mac_header(skb, 0);
- skb_set_network_header(skb, 0);
- skb_set_transport_header(skb, 0);
-
- skb->iif = sdata->dev->ifindex;
- skb->do_not_encrypt = !encrypt;
-
- dev_queue_xmit(skb);
-}
-
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band)
{
@@ -804,12 +779,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
- u8 *extra, size_t extra_len,
- const u8 *bssid, int encrypt)
+ u8 *extra, size_t extra_len, const u8 *bssid,
+ const u8 *key, u8 key_len, u8 key_idx)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
+ int err;
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + 6 + extra_len);
@@ -824,8 +800,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
memset(mgmt, 0, 24 + 6);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_AUTH);
- if (encrypt)
- mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
memcpy(mgmt->da, bssid, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -835,7 +809,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
if (extra)
memcpy(skb_put(skb, extra_len), extra, extra_len);
- ieee80211_tx_skb(sdata, skb, encrypt);
+ if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+ WARN_ON(err);
+ }
+
+ ieee80211_tx_skb(sdata, skb, 0);
}
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
@@ -1043,9 +1023,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 4fafb2d27c8..8a980f13694 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
-static int ieee80211_wep_encrypt(struct ieee80211_local *local,
- struct sk_buff *skb,
- const u8 *key, int keylen, int keyidx)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ const u8 *key, int keylen, int keyidx)
{
u8 *iv;
size_t len;
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 85219ded870..fe29d7e5759 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_free(struct ieee80211_local *local);
void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ const u8 *key, int keylen, int keyidx);
int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 116a923b14d..b19b7696f3a 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -85,10 +85,8 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
return ieee802_1d_to_ac[skb->priority];
}
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
+void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 queue;
u8 tid;
@@ -113,5 +111,5 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
*p = 0;
}
- return queue;
+ skb_set_queue_mapping(skb, queue);
}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 7520d2e014d..d4fd87ca511 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -20,6 +20,7 @@
extern const int ieee802_1d_to_ac[8];
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb);
+void ieee80211_select_queue(struct ieee80211_local *local,
+ struct sk_buff *skb);
#endif /* _WME_H */