Commit af6b6374 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: generalise work handling

In order to use auth/assoc for different purposes
other than MLME, it needs to be split up. For other
purposes, a generic work handling (potentially on
another channel) will be useful.

To achieve that, this patch moves much of the MLME
work handling out of mlme into a new work API. The
API can currently handle probing a specific AP,
authentication and association. The MLME previously
handled probe/authentication as one step and will
continue to do so, but they are separate in the new
work handling.

Work items are RCU-managed to be able to check for
existence of an item for a specific frame in the RX
path, but they can be re-used which the MLME right
now will do for its combined probe/auth step.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f679f65d
...@@ -9,7 +9,7 @@ mac80211-y := \ ...@@ -9,7 +9,7 @@ mac80211-y := \
scan.o \ scan.o \
ht.o agg-tx.o agg-rx.o \ ht.o agg-tx.o agg-rx.o \
ibss.o \ ibss.o \
mlme.o \ mlme.o work.o \
iface.o \ iface.o \
rate.o \ rate.o \
michael.o \ michael.o \
......
...@@ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); ...@@ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
/* STA attributes */ /* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode) enum ieee80211_smps_mode smps_mode)
...@@ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) ...@@ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(aid, sta); DEBUGFS_ADD(aid, sta);
DEBUGFS_ADD(capab, sta);
DEBUGFS_ADD_MODE(smps, 0600); DEBUGFS_ADD_MODE(smps, 0600);
} }
......
...@@ -228,41 +228,63 @@ struct mesh_preq_queue { ...@@ -228,41 +228,63 @@ struct mesh_preq_queue {
}; };
enum ieee80211_work_type { enum ieee80211_work_type {
IEEE80211_WORK_AUTH_PROBE, IEEE80211_WORK_DIRECT_PROBE,
IEEE80211_WORK_AUTH, IEEE80211_WORK_AUTH,
IEEE80211_WORK_ASSOC, IEEE80211_WORK_ASSOC,
}; };
/**
* enum work_done_result - indicates what to do after work was done
*
* @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
* @WORK_DONE_REQUEUE: This work item was reset to be reused, and
* should be requeued.
*/
enum work_done_result {
WORK_DONE_DESTROY,
WORK_DONE_REQUEUE,
};
struct ieee80211_work { struct ieee80211_work {
struct list_head list; struct list_head list;
struct rcu_head rcu_head;
struct ieee80211_sub_if_data *sdata;
enum work_done_result (*done)(struct ieee80211_work *wk,
struct sk_buff *skb);
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
/* XXX: chan type? -- right now not really needed */ /* XXX: chan type? -- right now not really needed */
unsigned long timeout; unsigned long timeout;
enum ieee80211_work_type type; enum ieee80211_work_type type;
u8 filter_ta[ETH_ALEN];
union { union {
struct { struct {
int tries; int tries;
u16 algorithm, transaction; u16 algorithm, transaction;
u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len; u8 ssid_len;
u8 bssid[ETH_ALEN];
u8 key[WLAN_KEY_LEN_WEP104]; u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx; u8 key_len, key_idx;
bool privacy; bool privacy;
} auth; } probe_auth;
struct { struct {
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
const u8 *supp_rates; const u8 *supp_rates;
const u8 *ht_information_ie; const u8 *ht_information_ie;
enum ieee80211_smps_mode smps;
int tries; int tries;
u16 capability; u16 capability;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len; u8 ssid_len;
u8 supp_rates_len; u8 supp_rates_len;
bool wmm_used; bool wmm_used, use_11n;
} assoc; } assoc;
}; };
...@@ -276,17 +298,11 @@ enum ieee80211_sta_flags { ...@@ -276,17 +298,11 @@ enum ieee80211_sta_flags {
IEEE80211_STA_BEACON_POLL = BIT(0), IEEE80211_STA_BEACON_POLL = BIT(0),
IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONNECTION_POLL = BIT(1),
IEEE80211_STA_CONTROL_PORT = BIT(2), IEEE80211_STA_CONTROL_PORT = BIT(2),
IEEE80211_STA_WMM_ENABLED = BIT(3),
IEEE80211_STA_DISABLE_11N = BIT(4), IEEE80211_STA_DISABLE_11N = BIT(4),
IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_CSA_RECEIVED = BIT(5),
IEEE80211_STA_MFP_ENABLED = BIT(6), IEEE80211_STA_MFP_ENABLED = BIT(6),
}; };
/* flags for MLME request */
enum ieee80211_sta_request {
IEEE80211_STA_REQ_SCAN,
};
struct ieee80211_if_managed { struct ieee80211_if_managed {
struct timer_list timer; struct timer_list timer;
struct timer_list conn_mon_timer; struct timer_list conn_mon_timer;
...@@ -302,12 +318,10 @@ struct ieee80211_if_managed { ...@@ -302,12 +318,10 @@ struct ieee80211_if_managed {
struct mutex mtx; struct mutex mtx;
struct ieee80211_bss *associated; struct ieee80211_bss *associated;
struct list_head work_list;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
u16 aid; u16 aid;
u16 capab;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
...@@ -316,8 +330,6 @@ struct ieee80211_if_managed { ...@@ -316,8 +330,6 @@ struct ieee80211_if_managed {
enum ieee80211_smps_mode req_smps, /* requested smps mode */ enum ieee80211_smps_mode req_smps, /* requested smps mode */
ap_smps; /* smps mode AP thinks we're in */ ap_smps; /* smps mode AP thinks we're in */
unsigned long request;
unsigned int flags; unsigned int flags;
u32 beacon_crc; u32 beacon_crc;
...@@ -583,6 +595,15 @@ struct ieee80211_local { ...@@ -583,6 +595,15 @@ struct ieee80211_local {
const struct ieee80211_ops *ops; const struct ieee80211_ops *ops;
/*
* work stuff, potentially off-channel (in the future)
*/
struct mutex work_mtx;
struct list_head work_list;
struct timer_list work_timer;
struct work_struct work_work;
struct sk_buff_head work_skb_queue;
/* /*
* private workqueue to mac80211. mac80211 makes this accessible * private workqueue to mac80211. mac80211 makes this accessible
* via ieee80211_queue_work() * via ieee80211_queue_work()
...@@ -1127,6 +1148,14 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, ...@@ -1127,6 +1148,14 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
void ieee80211_recalc_smps(struct ieee80211_local *local, void ieee80211_recalc_smps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *forsdata); struct ieee80211_sub_if_data *forsdata);
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);
void ieee80211_add_work(struct ieee80211_work *wk);
void free_work(struct ieee80211_work *wk);
void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
#ifdef CONFIG_MAC80211_NOINLINE #ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline #define debug_noinline noinline
#else #else
......
...@@ -361,6 +361,11 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -361,6 +361,11 @@ static int ieee80211_stop(struct net_device *dev)
*/ */
netif_stop_queue(dev); netif_stop_queue(dev);
/*
* Purge work for this interface.
*/
ieee80211_work_purge(sdata);
/* /*
* Now delete all active aggregation sessions. * Now delete all active aggregation sessions.
*/ */
...@@ -928,6 +933,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) ...@@ -928,6 +933,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int count = 0; int count = 0;
if (!list_empty(&local->work_list))
return ieee80211_idle_off(local, "working");
if (local->scanning) if (local->scanning)
return ieee80211_idle_off(local, "scanning"); return ieee80211_idle_off(local, "scanning");
...@@ -936,8 +944,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) ...@@ -936,8 +944,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
continue; continue;
/* do not count disabled managed interfaces */ /* do not count disabled managed interfaces */
if (sdata->vif.type == NL80211_IFTYPE_STATION && if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!sdata->u.mgd.associated && !sdata->u.mgd.associated)
list_empty(&sdata->u.mgd.work_list))
continue; continue;
/* do not count unused IBSS interfaces */ /* do not count unused IBSS interfaces */
if (sdata->vif.type == NL80211_IFTYPE_ADHOC && if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
......
...@@ -395,6 +395,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ...@@ -395,6 +395,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
ieee80211_work_init(local);
INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->restart_work, ieee80211_restart_work);
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
......
This diff is collapsed.
...@@ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) ...@@ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{ {
struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
ieee80211_rx_result rxs;
if (!(rx->flags & IEEE80211_RX_RA_MATCH)) if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR; return RX_DROP_MONITOR;
...@@ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) ...@@ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
return RX_DROP_MONITOR; return RX_DROP_MONITOR;
rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
if (rxs != RX_CONTINUE)
return rxs;
if (ieee80211_vif_is_mesh(&sdata->vif)) if (ieee80211_vif_is_mesh(&sdata->vif))
return ieee80211_mesh_rx_mgmt(sdata, rx->skb); return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
......
...@@ -434,7 +434,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ...@@ -434,7 +434,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req) struct cfg80211_scan_request *req)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int rc; int rc;
if (local->scan_req) if (local->scan_req)
...@@ -464,11 +463,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ...@@ -464,11 +463,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->scan_req = req; local->scan_req = req;
local->scan_sdata = sdata; local->scan_sdata = sdata;
if (req != local->int_scan_req && if (!list_empty(&local->work_list)) {
sdata->vif.type == NL80211_IFTYPE_STATION && /* wait for the work to finish/time out */
!list_empty(&ifmgd->work_list)) {
/* actually wait for the work it's doing to finish/time out */
set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
return 0; return 0;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment