summaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/driver-ops.h14
-rw-r--r--net/mac80211/ieee80211_i.h8
-rw-r--r--net/mac80211/iface.c41
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mesh.c49
-rw-r--r--net/mac80211/mlme.c28
-rw-r--r--net/mac80211/pm.c13
-rw-r--r--net/mac80211/rc80211_minstrel.h1
-rw-r--r--net/mac80211/rc80211_minstrel_debugfs.c2
-rw-r--r--net/mac80211/rx.c39
-rw-r--r--net/mac80211/scan.c9
-rw-r--r--net/mac80211/util.c10
12 files changed, 112 insertions, 104 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d231c9323ad1..020a94a31106 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
static inline int drv_start(struct ieee80211_local *local)
{
- int ret = local->ops->start(&local->hw);
+ int ret;
+
+ local->started = true;
+ smp_mb();
+ ret = local->ops->start(&local->hw);
trace_drv_start(local, ret);
return ret;
}
@@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local)
{
local->ops->stop(&local->hw);
trace_drv_stop(local);
+
+ /* sync away all work on the tasklet before clearing started */
+ tasklet_disable(&local->tasklet);
+ tasklet_enable(&local->tasklet);
+
+ barrier();
+
+ local->started = false;
}
static inline int drv_add_interface(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 93e618a980d1..dbd8411cc1bd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -367,6 +367,10 @@ struct ieee80211_if_mesh {
u8 mesh_pm_id[4];
/* Congestion Control Mode Identifier */
u8 mesh_cc_id[4];
+ /* Synchronization Protocol Identifier */
+ u8 mesh_sp_id[4];
+ /* Authentication Protocol Identifier */
+ u8 mesh_auth_id[4];
/* Local mesh Destination Sequence Number */
u32 dsn;
/* Last used PREQ ID */
@@ -663,6 +667,9 @@ struct ieee80211_local {
*/
bool quiescing;
+ /* device is started */
+ bool started;
+
int tx_headroom; /* required headroom for hardware/radiotap */
/* Tasklet and skb queue to process calls from IRQ mode. All frames
@@ -1082,6 +1089,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
/* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local);
+void ieee80211_stop_device(struct ieee80211_local *local);
#ifdef CONFIG_PM
int __ieee80211_suspend(struct ieee80211_hw *hw);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b161301056df..f6005adcbf90 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev)
}
}
- if (local->open_count == 0) {
- tasklet_enable(&local->tx_pending_tasklet);
- tasklet_enable(&local->tasklet);
- }
-
/*
* set_multicast_list will be invoked by the networking core
* which will check whether any increments here were done in
@@ -502,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev)
}
/* fall through */
default:
- if (local->scan_sdata == sdata) {
- if (!local->ops->hw_scan)
- cancel_delayed_work_sync(&local->scan_work);
- /*
- * The software scan can no longer run now, so we can
- * clear out the scan_sdata reference. However, the
- * hardware scan may still be running. The complete
- * function must be prepared to handle a NULL value.
- */
- local->scan_sdata = NULL;
- /*
- * The memory barrier guarantees that another CPU
- * that is hardware-scanning will now see the fact
- * that this interface is gone.
- */
- smp_mb();
- /*
- * If software scanning, complete the scan but since
- * the scan_sdata is NULL already don't send out a
- * scan event to userspace -- the scan is incomplete.
- */
- if (test_bit(SCAN_SW_SCANNING, &local->scanning))
- ieee80211_scan_completed(&local->hw, true);
- }
+ if (local->scan_sdata == sdata)
+ ieee80211_scan_cancel(local);
/*
* Disable beaconing for AP and mesh, IBSS can't
@@ -552,14 +525,8 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
- drv_stop(local);
-
- ieee80211_led_radio(local, false);
-
- flush_workqueue(local->workqueue);
-
- tasklet_disable(&local->tx_pending_tasklet);
- tasklet_disable(&local->tasklet);
+ ieee80211_clear_tx_pending(local);
+ ieee80211_stop_device(local);
/* no reconfiguring after stop! */
hw_reconf_flags = 0;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index dd3b0816614d..797f53942e5f 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->pending[i]);
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
- tasklet_disable(&local->tx_pending_tasklet);
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);
- tasklet_disable(&local->tasklet);
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 3185e18c8214..f7364e56f1ee 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -18,8 +18,11 @@
#define PP_OFFSET 1 /* Path Selection Protocol */
#define PM_OFFSET 5 /* Path Selection Metric */
#define CC_OFFSET 9 /* Congestion Control Mode */
-#define CAPAB_OFFSET 17
-#define ACCEPT_PLINKS 0x80
+#define SP_OFFSET 13 /* Synchronization Protocol */
+#define AUTH_OFFSET 17 /* Authentication Protocol */
+#define CAPAB_OFFSET 22
+#define CAPAB_ACCEPT_PLINKS 0x80
+#define CAPAB_FORWARDING 0x10
#define TMR_RUNNING_HK 0
#define TMR_RUNNING_MP 1
@@ -84,7 +87,9 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
- memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+ memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 &&
+ memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 &&
+ memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0)
return true;
return false;
@@ -97,7 +102,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
*/
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
{
- return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
+ return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0;
}
/**
@@ -123,11 +128,18 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
void mesh_ids_set_default(struct ieee80211_if_mesh *sta)
{
- u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
-
- memcpy(sta->mesh_pp_id, def_id, 4);
- memcpy(sta->mesh_pm_id, def_id, 4);
- memcpy(sta->mesh_cc_id, def_id, 4);
+ u8 oui[3] = {0x00, 0x0F, 0xAC};
+
+ memcpy(sta->mesh_pp_id, oui, sizeof(oui));
+ memcpy(sta->mesh_pm_id, oui, sizeof(oui));
+ memcpy(sta->mesh_cc_id, oui, sizeof(oui));
+ memcpy(sta->mesh_sp_id, oui, sizeof(oui));
+ memcpy(sta->mesh_auth_id, oui, sizeof(oui));
+ sta->mesh_pp_id[sizeof(oui)] = 0;
+ sta->mesh_pm_id[sizeof(oui)] = 0;
+ sta->mesh_cc_id[sizeof(oui)] = 0xff;
+ sta->mesh_sp_id[sizeof(oui)] = 0xff;
+ sta->mesh_auth_id[sizeof(oui)] = 0x0;
}
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@@ -245,7 +257,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
if (sdata->u.mesh.mesh_id_len)
memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
- pos = skb_put(skb, 21);
+ pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
*pos++ = WLAN_EID_MESH_CONFIG;
*pos++ = IEEE80211_MESH_CONFIG_LEN;
/* Version */
@@ -263,15 +275,22 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
memcpy(pos, sdata->u.mesh.mesh_cc_id, 4);
pos += 4;
- /* Channel precedence:
- * Not running simple channel unification protocol
- */
- memset(pos, 0x00, 4);
+ /* Synchronization protocol identifier */
+ memcpy(pos, sdata->u.mesh.mesh_sp_id, 4);
pos += 4;
+ /* Authentication Protocol identifier */
+ memcpy(pos, sdata->u.mesh.mesh_auth_id, 4);
+ pos += 4;
+
+ /* Mesh Formation Info */
+ memset(pos, 0x00, 1);
+ pos += 1;
+
/* Mesh capability */
sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
- *pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+ *pos = CAPAB_FORWARDING;
+ *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
return;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c374d2d73fa4..97a278a2f48e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2123,25 +2123,9 @@ static void ieee80211_sta_work(struct work_struct *work)
}
}
- list_for_each_entry(wk, &ifmgd->work_list, list) {
- if (wk->state != IEEE80211_MGD_STATE_IDLE) {
- anybusy = true;
- break;
- }
- }
ieee80211_recalc_idle(local);
- if (!anybusy) {
- mutex_unlock(&ifmgd->mtx);
-
- if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
- ieee80211_queue_delayed_work(&local->hw,
- &local->scan_work,
- round_jiffies_relative(0));
- return;
- }
-
list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
if (time_is_after_jiffies(wk->timeout)) {
/*
@@ -2187,6 +2171,18 @@ static void ieee80211_sta_work(struct work_struct *work)
}
}
+ list_for_each_entry(wk, &ifmgd->work_list, list) {
+ if (wk->state != IEEE80211_MGD_STATE_IDLE) {
+ anybusy = true;
+ break;
+ }
+ }
+ if (!anybusy &&
+ test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
+ ieee80211_queue_delayed_work(&local->hw,
+ &local->scan_work,
+ round_jiffies_relative(0));
+
mutex_unlock(&ifmgd->mtx);
list_for_each_entry_safe(wk, tmp, &free_work, list) {
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index a5d2f1fb4417..e535f1c988fe 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -107,17 +107,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
}
/* stop hardware - this must stop RX */
- if (local->open_count) {
- ieee80211_led_radio(local, false);
- drv_stop(local);
- }
-
- /*
- * flush again, in case driver queued work -- it
- * shouldn't be doing (or cancel everything in the
- * stop callback) that but better safe than sorry.
- */
- flush_workqueue(local->workqueue);
+ if (local->open_count)
+ ieee80211_stop_device(local);
local->suspended = true;
/* need suspended to be visible before quiescing is false */
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 869fe0ef951d..38bf4168fc3a 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -33,7 +33,6 @@ struct minstrel_rate {
/* per-rate throughput */
u32 cur_tp;
- u32 throughput;
u64 succ_hist;
u64 att_hist;
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index 98f480708050..3d72ec5730d4 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -83,7 +83,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
p += sprintf(p, "%3u%s", mr->bitrate / 2,
(mr->bitrate & 1 ? ".5" : " "));
- tp = ((mr->cur_tp * 96) / 18000) >> 10;
+ tp = mr->cur_tp / ((18000 << 10) / 96);
prob = mr->cur_prob / 18;
eprob = mr->probability / 18;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7065fd7e7ba2..c01588f9d453 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2440,24 +2440,20 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
* This is the receive path handler. It is called by a low level driver when an
* 802.11 MPDU is received from the hardware.
*/
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- if (status->band < 0 ||
- status->band >= IEEE80211_NUM_BANDS) {
- WARN_ON(1);
- return;
- }
+ if (WARN_ON(status->band < 0 ||
+ status->band >= IEEE80211_NUM_BANDS))
+ goto drop;
sband = local->hw.wiphy->bands[status->band];
- if (!sband) {
- WARN_ON(1);
- return;
- }
+ if (WARN_ON(!sband))
+ goto drop;
/*
* If we're suspending, it is possible although not too likely
@@ -2466,16 +2462,21 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
* that might, for example, cause stations to be added or other
* driver callbacks be invoked.
*/
- if (unlikely(local->quiescing || local->suspended)) {
- kfree_skb(skb);
- return;
- }
+ if (unlikely(local->quiescing || local->suspended))
+ goto drop;
+
+ /*
+ * The same happens when we're not even started,
+ * but that's worth a warning.
+ */
+ if (WARN_ON(!local->started))
+ goto drop;
if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= 76))
- return;
+ goto drop;
/* HT rates are not in the table - use the highest legacy rate
* for now since other parts of mac80211 may not yet be fully
* MCS aware. */
@@ -2483,7 +2484,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
} else {
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= sband->n_bitrates))
- return;
+ goto drop;
rate = &sband->bitrates[status->rate_idx];
}
@@ -2522,8 +2523,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
__ieee80211_rx_handle_packet(hw, skb, rate);
rcu_read_unlock();
+
+ return;
+ drop:
+ kfree_skb(skb);
}
-EXPORT_SYMBOL(__ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_rx);
/* This is a version of the rx handler that can be called from hard irq
* context. Post the skb on the queue and schedule the tasklet */
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 1e04be6b9129..039901109fa1 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (local->scan_req != local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL;
+ local->scan_sdata = NULL;
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
local->scanning = 0;
@@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work)
int rc;
local->scan_req = NULL;
+ local->scan_sdata = NULL;
rc = __ieee80211_start_scan(sdata, req);
mutex_unlock(&local->scan_mtx);
@@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
- bool swscan;
+ bool abortscan;
cancel_delayed_work_sync(&local->scan_work);
@@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* queued -- mostly at suspend under RTNL.
*/
mutex_lock(&local->scan_mtx);
- swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
+ abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+ (!local->scanning && local->scan_req);
mutex_unlock(&local->scan_mtx);
- if (swscan)
+ if (abortscan)
ieee80211_scan_completed(&local->hw, true);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5eb306377c63..dd6564321369 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1007,6 +1007,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
return supp_rates;
}
+void ieee80211_stop_device(struct ieee80211_local *local)
+{
+ ieee80211_led_radio(local, false);
+
+ cancel_work_sync(&local->reconfig_filter);
+ drv_stop(local);
+
+ flush_workqueue(local->workqueue);
+}
+
int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;