diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 158 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 1 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 15 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/key.c | 1 | ||||
-rw-r--r-- | net/mac80211/main.c | 6 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 1 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 189 | ||||
-rw-r--r-- | net/mac80211/pm.c | 2 | ||||
-rw-r--r-- | net/mac80211/rx.c | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 8 | ||||
-rw-r--r-- | net/mac80211/status.c | 1 | ||||
-rw-r--r-- | net/mac80211/tx.c | 32 | ||||
-rw-r--r-- | net/mac80211/util.c | 2 |
15 files changed, 220 insertions, 200 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c3de921c8cfd..6a77d4c910f9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -489,27 +489,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) -{ - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - - bss_conf->ssid_len = params->ssid_len; - - if (params->ssid_len) - memcpy(bss_conf->ssid, params->ssid, params->ssid_len); - - bss_conf->hidden_ssid = - (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); -} - static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, - u8 *resp, size_t resp_len) + const u8 *resp, size_t resp_len) { struct sk_buff *new, *old; if (!resp || !resp_len) - return -EINVAL; + return 1; old = rtnl_dereference(sdata->u.ap.probe_resp); @@ -520,50 +506,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, memcpy(skb_put(new, resp_len), resp, resp_len); rcu_assign_pointer(sdata->u.ap.probe_resp, new); - synchronize_rcu(); - - if (old) + if (old) { + /* TODO: use call_rcu() */ + synchronize_rcu(); dev_kfree_skb(old); + } return 0; } -/* - * This handles both adding a beacon and setting new beacon info - */ -static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) +static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params) { struct beacon_data *new, *old; int new_head_len, new_tail_len; - int size; - int err = -EINVAL; - u32 changed = 0; + int size, err; + u32 changed = BSS_CHANGED_BEACON; old = rtnl_dereference(sdata->u.ap.beacon); - /* head must not be zero-length */ - if (params->head && !params->head_len) - return -EINVAL; - - /* - * This is a kludge. beacon interval should really be part - * of the beacon information. - */ - if (params->interval && - (sdata->vif.bss_conf.beacon_int != params->interval)) { - sdata->vif.bss_conf.beacon_int = params->interval; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_INT); - } - /* Need to have a beacon head if we don't have one yet */ if (!params->head && !old) - return err; - - /* sorry, no way to start beaconing without dtim period */ - if (!params->dtim_period && !old) - return err; + return -EINVAL; /* new or old head? */ if (params->head) @@ -586,12 +550,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, /* start filling the new info now */ - /* new or old dtim period? */ - if (params->dtim_period) - new->dtim_period = params->dtim_period; - else - new->dtim_period = old->dtim_period; - /* * pointers go into the block we allocated, * memory is | beacon_data | head | tail | @@ -614,46 +572,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, if (old) memcpy(new->tail, old->tail, new_tail_len); - sdata->vif.bss_conf.dtim_period = new->dtim_period; - - rcu_assign_pointer(sdata->u.ap.beacon, new); - - synchronize_rcu(); - - kfree(old); - err = ieee80211_set_probe_resp(sdata, params->probe_resp, params->probe_resp_len); - if (!err) + if (err < 0) + return err; + if (err == 0) changed |= BSS_CHANGED_AP_PROBE_RESP; - ieee80211_config_ap_ssid(sdata, params); - changed |= BSS_CHANGED_BEACON_ENABLED | - BSS_CHANGED_BEACON | - BSS_CHANGED_SSID; + rcu_assign_pointer(sdata->u.ap.beacon, new); + + if (old) + kfree_rcu(old, rcu_head); - ieee80211_bss_info_change_notify(sdata, changed); - return 0; + return changed; } -static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *params) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct beacon_data *old; struct ieee80211_sub_if_data *vlan; - int ret; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u32 changed = BSS_CHANGED_BEACON_INT | + BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON | + BSS_CHANGED_SSID; + int err; old = rtnl_dereference(sdata->u.ap.beacon); if (old) return -EALREADY; - ret = ieee80211_config_beacon(sdata, params); - if (ret) - return ret; - /* * Apply control port protocol, this allows us to * not encrypt dynamic WEP control frames. @@ -667,14 +616,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_no_encrypt; } + sdata->vif.bss_conf.beacon_int = params->beacon_interval; + sdata->vif.bss_conf.dtim_period = params->dtim_period; + + sdata->vif.bss_conf.ssid_len = params->ssid_len; + if (params->ssid_len) + memcpy(sdata->vif.bss_conf.ssid, params->ssid, + params->ssid_len); + sdata->vif.bss_conf.hidden_ssid = + (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon); + if (err < 0) + return err; + changed |= err; + + ieee80211_bss_info_change_notify(sdata, changed); + return 0; } -static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *params) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -682,10 +649,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, if (!old) return -ENOENT; - return ieee80211_config_beacon(sdata, params); + err = ieee80211_assign_beacon(sdata, params); + if (err < 0) + return err; + ieee80211_bss_info_change_notify(sdata, err); + return 0; } -static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; @@ -697,10 +668,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) return -ENOENT; RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(old); + + kfree_rcu(old, rcu_head); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + return 0; } @@ -1623,19 +1595,15 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req, - void *cookie) + struct cfg80211_deauth_request *req) { - return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), - req, cookie); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req, - void *cookie) + struct cfg80211_disassoc_request *req) { - return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), - req, cookie); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, @@ -2699,9 +2667,9 @@ struct cfg80211_ops mac80211_config_ops = { .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, .set_default_mgmt_key = ieee80211_config_default_mgmt_key, - .add_beacon = ieee80211_add_beacon, - .set_beacon = ieee80211_set_beacon, - .del_beacon = ieee80211_del_beacon, + .start_ap = ieee80211_start_ap, + .change_beacon = ieee80211_change_beacon, + .stop_ap = ieee80211_stop_ap, .add_station = ieee80211_add_station, .del_station = ieee80211_del_station, .change_station = ieee80211_change_station, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8361da4b36ab..7f9ac577600a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -20,7 +20,6 @@ #include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include <net/mac80211.h> -#include <asm/unaligned.h> #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 74594f012cd3..cee0c7493fd0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,7 +228,7 @@ struct ieee80211_rx_data { struct beacon_data { u8 *head, *tail; int head_len, tail_len; - int dtim_period; + struct rcu_head rcu_head; }; struct ieee80211_if_ap { @@ -1128,12 +1128,6 @@ static inline struct ieee80211_local *hw_to_local( return container_of(hw, struct ieee80211_local, hw); } -static inline struct ieee80211_hw *local_to_hw( - struct ieee80211_local *local) -{ - return &local->hw; -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { @@ -1156,11 +1150,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req); int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req, - void *cookie); + struct cfg80211_deauth_request *req); int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req, - void *cookie); + struct cfg80211_disassoc_request *req); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); @@ -1178,6 +1170,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); +void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata); /* IBSS code */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index daa50ea15f46..620ca8d2ad42 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -644,6 +644,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rmc_free(sdata); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + ieee80211_mgd_teardown(sdata); flushed = sta_info_flush(local, sdata); WARN_ON(flushed); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index e8616b3ff636..5bb600d93d77 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/export.h> #include <net/mac80211.h> +#include <asm/unaligned.h> #include "ieee80211_i.h" #include "driver-ops.h" #include "debugfs_key.h" diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2306d7514fff..36fa8051296c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -286,11 +286,11 @@ static void ieee80211_tasklet_handler(unsigned long data) /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; - ieee80211_rx(local_to_hw(local), skb); + ieee80211_rx(&local->hw, skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), skb); + ieee80211_tx_status(&local->hw, skb); break; case IEEE80211_EOSP_MSG: eosp_data = (void *)skb->cb; @@ -668,7 +668,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ieee80211_hw_roc_setup(local); - return local_to_hw(local); + return &local->hw; } EXPORT_SYMBOL(ieee80211_alloc_hw); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index bd14bd26a2b6..c7e5c49471e5 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -13,7 +13,6 @@ #include <linux/types.h> #include <linux/jhash.h> -#include <asm/unaligned.h> #include "ieee80211_i.h" diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c27dec904963..31bc762f209d 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -8,6 +8,7 @@ */ #include <linux/slab.h> +#include <asm/unaligned.h> #include "wme.h" #include "mesh.h" diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 52133dab9297..caf97f5a2937 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -88,6 +88,8 @@ MODULE_PARM_DESC(probe_wait_ms, #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 +#define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */) + /* * All cfg80211 functions have to be called outside a locked * section so that they can acquire a lock themselves... This @@ -612,47 +614,42 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, u16 stype, u16 reason, - void *cookie, bool send_frame) + const u8 *bssid, u16 stype, + u16 reason, bool send_frame, + u8 *frame_buf) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); - if (!skb) - return; - - skb_reserve(skb, local->hw.extra_tx_headroom); + struct ieee80211_mgmt *mgmt = (void *)frame_buf; - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); + /* build frame */ + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); + mgmt->duration = 0; /* initialize only */ + mgmt->seq_ctrl = 0; /* initialize only */ memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); - skb_put(skb, 2); /* u.deauth.reason_code == u.disassoc.reason_code */ mgmt->u.deauth.reason_code = cpu_to_le16(reason); - if (stype == IEEE80211_STYPE_DEAUTH) - if (cookie) - __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - else - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - else - if (cookie) - __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); - else - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); - if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + if (send_frame) { + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + DEAUTH_DISASSOC_LEN); + if (!skb) + return; - if (send_frame) + skb_reserve(skb, local->hw.extra_tx_headroom); + + /* copy in frame */ + memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN), + mgmt, DEAUTH_DISASSOC_LEN); + + if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) + IEEE80211_SKB_CB(skb)->flags |= + IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); - else - kfree_skb(skb); + } } void ieee80211_send_pspoll(struct ieee80211_local *local, @@ -1392,7 +1389,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool remove_sta, bool tx) + u16 stype, u16 reason, bool tx, + u8 *frame_buf) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1402,6 +1400,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); + if (WARN_ON_ONCE(tx && !frame_buf)) + return; + if (WARN_ON(!ifmgd->associated)) return; @@ -1435,6 +1436,19 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->sta_mtx); + /* deauthenticate/disassociate now */ + if (tx || frame_buf) + ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason, + tx, frame_buf); + + /* flush out frame */ + if (tx) + drv_flush(local, false); + + /* remove AP and TDLS peers */ + sta_info_flush(local, sdata); + + /* finally reset all BSS / config parameters */ changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); @@ -1474,10 +1488,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); - /* remove AP and TDLS peers */ - if (remove_sta) - sta_info_flush(local, sdata); - del_timer_sync(&sdata->u.mgd.conn_mon_timer); del_timer_sync(&sdata->u.mgd.bcn_mon_timer); del_timer_sync(&sdata->u.mgd.timer); @@ -1674,6 +1684,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; u8 bssid[ETH_ALEN]; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) { @@ -1686,17 +1697,16 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", sdata->name, bssid); - ieee80211_set_disassoc(sdata, true, true); + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + false, frame_buf); 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, true); + cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -1903,7 +1913,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", sdata->name, bssid, reason_code); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); @@ -1933,10 +1944,12 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", sdata->name, mgmt->sa, reason_code); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); + return RX_MGMT_CFG80211_DISASSOC; } @@ -2238,14 +2251,28 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } else { printk(KERN_DEBUG "%s: associated\n", sdata->name); - ieee80211_destroy_assoc_data(sdata, true); + /* tell driver about sync done first */ + if (assoc_data->synced) { + drv_finish_tx_sync(sdata->local, sdata, + assoc_data->bss->bssid, + IEEE80211_TX_SYNC_ASSOC); + assoc_data->synced = false; + } if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { /* oops -- internal error -- send timeout for now */ + ieee80211_destroy_assoc_data(sdata, true); sta_info_destroy_addr(sdata, mgmt->bssid); cfg80211_put_bss(*bss); return RX_MGMT_CFG80211_ASSOC_TIMEOUT; } + + /* + * destroy assoc_data afterwards, as otherwise an idle + * recalc after assoc_data is NULL but before associated + * is set can cause the interface to go idle + */ + ieee80211_destroy_assoc_data(sdata, true); } return RX_MGMT_CFG80211_RX_ASSOC; @@ -2681,19 +2708,20 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - ieee80211_set_disassoc(sdata, true, true); + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, + false, frame_buf); 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, reason, - NULL, true); + cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -2974,13 +3002,17 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) { + u32 flags; + if (sdata->vif.type == NL80211_IFTYPE_STATION) { sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL); /* let's probe the connection once */ - ieee80211_queue_work(&sdata->local->hw, - &sdata->u.mgd.monitor_work); + flags = sdata->local->hw.flags; + if (!(flags & IEEE80211_HW_CONNECTION_MONITOR)) + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.monitor_work); /* and do all the other regular work too */ ieee80211_queue_work(&sdata->local->hw, &sdata->work); } @@ -3044,7 +3076,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmgd->chswitch_timer); ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_restart_sta_timer(sdata); - ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); } #endif @@ -3174,7 +3205,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ifmgd->auth_data = auth_data; if (ifmgd->associated) - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); printk(KERN_DEBUG "%s: authenticate with %pM\n", sdata->name, req->bss->bssid); @@ -3252,7 +3283,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); if (ifmgd->associated) - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); if (ifmgd->auth_data && !ifmgd->auth_data->done) { err = -EBUSY; @@ -3422,32 +3453,35 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req, - void *cookie) + struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - bool assoc_bss = false; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); - if (ifmgd->associated && - memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { - ieee80211_set_disassoc(sdata, false, true); - assoc_bss = true; - } else if (ifmgd->auth_data) { + if (ifmgd->auth_data) { ieee80211_destroy_auth_data(sdata, false); mutex_unlock(&ifmgd->mtx); return 0; } - mutex_unlock(&ifmgd->mtx); - printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", + printk(KERN_DEBUG + "%s: deauthenticating from %pM by local choice (reason=%d)\n", sdata->name, req->bssid, req->reason_code); - ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, - req->reason_code, cookie, true); - if (assoc_bss) - sta_info_flush(sdata->local, sdata); + if (ifmgd->associated && + memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, + req->reason_code, true, frame_buf); + else + ieee80211_send_deauth_disassoc(sdata, req->bssid, + IEEE80211_STYPE_DEAUTH, + req->reason_code, true, + frame_buf); + mutex_unlock(&ifmgd->mtx); + + __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); @@ -3457,11 +3491,11 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req, - void *cookie) + struct cfg80211_disassoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 bssid[ETH_ALEN]; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); @@ -3480,14 +3514,12 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, sdata->name, req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); - ieee80211_set_disassoc(sdata, false, true); - + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, + req->reason_code, !req->local_state_change, + frame_buf); mutex_unlock(&ifmgd->mtx); - ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, - IEEE80211_STYPE_DISASSOC, req->reason_code, - cookie, !req->local_state_change); - sta_info_flush(sdata->local, sdata); + __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); @@ -3496,6 +3528,19 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return 0; } +void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + mutex_lock(&ifmgd->mtx); + if (ifmgd->assoc_data) + ieee80211_destroy_assoc_data(sdata, false); + if (ifmgd->auth_data) + ieee80211_destroy_auth_data(sdata, false); + del_timer_sync(&ifmgd->timer); + mutex_unlock(&ifmgd->mtx); +} + void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, enum nl80211_cqm_rssi_threshold_event rssi_event, gfp_t gfp) diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 2b53a5348ace..ef8eba1d736d 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) state = sta->sta_state; for (; state > IEEE80211_STA_NOTEXIST; state--) - WARN_ON(drv_sta_state(local, sdata, sta, + WARN_ON(drv_sta_state(local, sta->sdata, sta, state, state - 1)); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3ab85c02ef04..7a4ff02af261 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,6 +19,7 @@ #include <linux/export.h> #include <net/mac80211.h> #include <net/ieee80211_radiotap.h> +#include <asm/unaligned.h> #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4034ee616022..cd0f265f42e5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -865,8 +865,10 @@ int sta_info_flush(struct ieee80211_local *local, mutex_lock(&local->sta_mtx); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (!sdata || sdata == sta->sdata) + if (!sdata || sdata == sta->sdata) { WARN_ON(__sta_info_destroy(sta)); + ret++; + } } mutex_unlock(&local->sta_mtx); @@ -1048,7 +1050,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, * exchange. Also set EOSP to indicate this packet * ends the poll/service period. */ - info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE | + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; @@ -1175,7 +1177,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, * STA may still remain is PS mode after this frame * exchange. */ - info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE; + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; /* * Use MoreData flag to indicate whether there are diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d67f0b967f8a..c928e4a4effd 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -11,6 +11,7 @@ #include <linux/export.h> #include <net/mac80211.h> +#include <asm/unaligned.h> #include "ieee80211_i.h" #include "rate.h" #include "mesh.h" diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1be0ca2b5936..570737df2d22 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_local *local = tx->local; - if (unlikely(!sta || - ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_auth(hdr->frame_control) || - ieee80211_is_assoc_resp(hdr->frame_control) || - ieee80211_is_reassoc_resp(hdr->frame_control))) + if (unlikely(!sta)) return TX_CONTINUE; if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && - !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) { + !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { int ac = skb_get_queue_mapping(tx->skb); + /* only deauth, disassoc and action are bufferable MMPDUs */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_deauth(hdr->frame_control) && + !ieee80211_is_disassoc(hdr->frame_control) && + !ieee80211_is_action(hdr->frame_control)) { + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; + return TX_CONTINUE; + } + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", sta->sta.addr, sta->sta.aid, ac); @@ -625,7 +630,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) tx->local->hw.wiphy->frag_threshold); /* set up the tx rate control struct we give the RC algo */ - txrc.hw = local_to_hw(tx->local); + txrc.hw = &tx->local->hw; txrc.sband = sband; txrc.bss_conf = &tx->sdata->vif.bss_conf; txrc.skb = tx->skb; @@ -2206,7 +2211,8 @@ void ieee80211_tx_pending(unsigned long data) /* functions for drivers to get certain frames */ -static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, +static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, + struct ieee80211_if_ap *bss, struct sk_buff *skb, struct beacon_data *beacon) { @@ -2223,7 +2229,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, IEEE80211_MAX_AID+1); if (bss->dtim_count == 0) - bss->dtim_count = beacon->dtim_period - 1; + bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1; else bss->dtim_count--; @@ -2231,7 +2237,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = bss->dtim_count; - *pos++ = beacon->dtim_period; + *pos++ = sdata->vif.bss_conf.dtim_period; if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) aid0 = 1; @@ -2324,12 +2330,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); } else { unsigned long flags; spin_lock_irqsave(&local->tim_lock, flags); - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); spin_unlock_irqrestore(&local->tim_lock, flags); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 264397aee811..f6e4cef92021 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -753,7 +753,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); - for (queue = 0; queue < local_to_hw(local)->queues; queue++) { + for (queue = 0; queue < local->hw.queues; queue++) { /* Set defaults according to 802.11-2007 Table 7-37 */ aCWmax = 1023; if (use_11b) |