From 19cd67e2d51225b164560b54b85f943e07deee8a Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 14 Jun 2012 04:34:30 +0800 Subject: leds: Rename led_brightness_set() to led_set_brightness() Rename leds external interface led_brightness_set() to led_set_brightness(). This is the second phase of the change to reduce confusion between the leds internal and external interfaces that set brightness. With this change, now the external interface is led_set_brightness(). The first phase renamed the internal interface led_set_brightness() to __led_set_brightness(). There are no changes to the interface implementations. Signed-off-by: Shuah Khan Signed-off-by: Bryan Wu --- net/mac80211/led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 1bf7903496f8..bcffa6903129 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c @@ -276,7 +276,7 @@ static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) read_lock(&tpt_trig->trig.leddev_list_lock); list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) - led_brightness_set(led_cdev, LED_OFF); + led_set_brightness(led_cdev, LED_OFF); read_unlock(&tpt_trig->trig.leddev_list_lock); } -- cgit v1.2.1 From bae35d92b6a1b6fd8c699415ab90aeeea2a56bc3 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 24 Jul 2012 11:52:35 +0800 Subject: mac80211: don't re-init rate control when receiving mesh beacon Rate control is re-initialized whenever a beacon from a mesh peer received, breaking the algorithms and resulting in low performance. Return early from mesh_peer_init if we already established a link with this peer to avoid this. Signed-off-by: Chun-Yeow Yeoh [clarify commit message] Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index af671b984df3..fa642c794719 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -362,6 +362,11 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, spin_lock_bh(&sta->lock); sta->last_rx = jiffies; + if (sta->plink_state == NL80211_PLINK_ESTAB) { + spin_unlock_bh(&sta->lock); + return sta; + } + sta->sta.supp_rates[band] = rates; if (elems->ht_cap_elem && sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT) -- cgit v1.2.1 From d545daba5357c1ca377a4fe917ccf4de3a3031e0 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Tue, 24 Jul 2012 03:33:10 +0000 Subject: mac80211: VHT (11ac) association Insert VHT IEs into association frames to allow mac80211 to connect as a VHT client. Signed-off-by: Mahesh Palivela [clarify commit message] Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index bb61f7718c4c..3e2f03b1b50e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -359,6 +359,7 @@ enum ieee80211_sta_flags { IEEE80211_STA_NULLFUNC_ACKED = BIT(8), IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), IEEE80211_STA_DISABLE_40MHZ = BIT(10), + IEEE80211_STA_DISABLE_VHT = BIT(11), }; struct ieee80211_mgd_auth_data { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cef0c9e79aba..725258c20746 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -326,6 +326,26 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); } +static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, + struct ieee80211_supported_band *sband) +{ + u8 *pos; + u32 cap; + struct ieee80211_sta_vht_cap vht_cap; + + BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); + + memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); + + /* determine capability flags */ + cap = vht_cap.cap; + + /* reserve and fill IE */ + pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2); + ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); +} + static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; @@ -371,6 +391,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) 4 + /* power capability */ 2 + 2 * sband->n_channels + /* supported channels */ 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ + 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ assoc_data->ie_len + /* extra IEs */ 9, /* WMM */ GFP_KERNEL); @@ -503,6 +524,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, sband, local->oper_channel, ifmgd->ap_smps); + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) + ieee80211_add_vht_ie(sdata, skb, sband); + /* if present, add any custom non-vendor IEs that go after HT */ if (assoc_data->ie_len && assoc_data->ie) { noffset = ieee80211_ie_split_vendor(assoc_data->ie, @@ -3301,6 +3325,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; + ifmgd->flags &= ~IEEE80211_STA_DISABLE_VHT; ifmgd->beacon_crc_valid = false; @@ -3316,13 +3341,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; netdev_info(sdata->dev, - "disabling HT due to WEP/TKIP use\n"); + "disabling HT/VHT due to WEP/TKIP use\n"); } } - if (req->flags & ASSOC_REQ_DISABLE_HT) + if (req->flags & ASSOC_REQ_DISABLE_HT) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; + } /* Also disable HT if we don't support it or the AP doesn't use WMM */ sband = local->hw.wiphy->bands[req->bss->channel->band]; @@ -3333,6 +3361,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, "disabling HT as WMM/QoS is not supported\n"); } + /* disable VHT if we don't support it or the AP doesn't use WMM */ + if (!sband->vht_cap.vht_supported || + local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; + netdev_info(sdata->dev, + "disabling VHT as WMM/QoS is not supported\n"); + } + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); -- cgit v1.2.1 From 7eeff74c29259e9cb7765e3845c0b74057f744da Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2012 10:27:27 +0200 Subject: mac80211: don't react to beacon loss if HW monitoring If the HW is monitoring connection loss (as advertised by IEEE80211_HW_CONNECTION_MONITOR) but not filtering beacons (IEEE80211_VIF_BEACON_FILTER) then mac80211 will still start the beacon loss timer and if a few beacons are lost, e.g. due to scanning, drop the connection. If the hardware doesn't advertise connection monitoring, then it won't drop the connection right away but probe the AP, which is intended, but due to the logic in the timer when connection monitoring is done it assumes the connection was actually lost. Fix this problem by not starting the timer when the HW does connection monitoring. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 725258c20746..81b2269e8f3a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -146,6 +146,9 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) return; + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) + return; + mod_timer(&sdata->u.mgd.bcn_mon_timer, round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); } -- cgit v1.2.1 From 8c7d857c4a4a552d8d3e1b2e24e1864ec2989285 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Jul 2012 01:42:36 +0300 Subject: mac80211: don't call mgd_prepare_tx when associated This doesn't make any sense since we are expected to be on the medium or at least to Tx only when we are on the right channel and the AP/GO can hear us. Move the call to mgd_prepare_tx() for deauth to be only done in case we're sending a deauth while not associated. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 81b2269e8f3a..f0d6fa283071 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -610,8 +610,6 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - drv_mgd_prepare_tx(local, sdata); - ieee80211_tx_skb(sdata, skb); } } @@ -3504,14 +3502,17 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, req->bssid, req->reason_code); if (ifmgd->associated && - ether_addr_equal(ifmgd->associated->bssid, req->bssid)) + ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, req->reason_code, true, frame_buf); - else + } else { + drv_mgd_prepare_tx(sdata->local, sdata); 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); -- cgit v1.2.1 From ab09587740fddf6b4116be7b6716ab47f34d2634 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 27 Jul 2012 12:33:22 +0300 Subject: mac80211: add PS flag to bss_conf Currently, ps mode is indicated per device (rather than per interface), which doesn't make a lot of sense. Moreover, there are subtle bugs caused by the inability to indicate ps change along with other changes (e.g. when the AP deauth us, we'd like to indicate CHANGED_PS | CHANGED_ASSOC, as changing PS before notifying about disassociation will result in null-packets being sent (if IEEE80211_HW_SUPPORTS_DYNAMIC_PS) while the sta is already disconnected.) Keep the current per-device notifications, and add parallel per-vif notifications. In order to keep it simple, the per-device ps and the per-vif ps are orthogonal - the per-vif ps configuration is determined only by the user configuration (enable/disable) and the connection state, and is not affected by other vifs state and (temporary) dynamic_ps/offchannel operations (unlike per-device ps). Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 6 ++++-- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 15 +++++++++++++++ net/mac80211/util.c | 3 ++- 4 files changed, 22 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d41974aacf51..06b8d39780e9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1285,9 +1285,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, mutex_unlock(&local->sta_mtx); if (sdata->vif.type == NL80211_IFTYPE_STATION && - params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) + params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { ieee80211_recalc_ps(local, -1); - + ieee80211_recalc_ps_vif(sdata); + } return 0; } @@ -2079,6 +2080,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); ieee80211_recalc_ps(local, -1); + ieee80211_recalc_ps_vif(sdata); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3e2f03b1b50e..8e65ad9c870a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1203,6 +1203,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); +void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); int ieee80211_max_network_latency(struct notifier_block *nb, unsigned long data, void *dummy); int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f0d6fa283071..ea46c6446450 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1032,6 +1032,16 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) ieee80211_change_ps(local); } +void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) +{ + bool ps_allowed = ieee80211_powersave_allowed(sdata); + + if (sdata->vif.bss_conf.ps != ps_allowed) { + sdata->vif.bss_conf.ps = ps_allowed; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS); + } +} + void ieee80211_dynamic_ps_disable_work(struct work_struct *work) { struct ieee80211_local *local = @@ -1335,6 +1345,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_smps(local); mutex_unlock(&local->iflist_mtx); + ieee80211_recalc_ps_vif(sdata); + netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); } @@ -1396,6 +1408,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } local->ps_sdata = NULL; + /* disable per-vif ps */ + ieee80211_recalc_ps_vif(sdata); + /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ if (tx) drv_flush(local, false); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 39b82fee4904..037d148e9f19 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1359,7 +1359,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: changed |= BSS_CHANGED_ASSOC | - BSS_CHANGED_ARP_FILTER; + BSS_CHANGED_ARP_FILTER | + BSS_CHANGED_PS; mutex_lock(&sdata->u.mgd.mtx); ieee80211_bss_info_change_notify(sdata, changed); mutex_unlock(&sdata->u.mgd.mtx); -- cgit v1.2.1 From 36323f817af0376c78612cfdab714b0feb05fea5 Mon Sep 17 00:00:00 2001 From: Thomas Huehn Date: Mon, 23 Jul 2012 21:33:42 +0200 Subject: mac80211: move TX station pointer and restructure TX Remove the control.sta pointer from ieee80211_tx_info to free up sufficient space in the TX skb control buffer for the upcoming Transmit Power Control (TPC). Instead, the pointer is now on the stack in a new control struct that is passed as a function parameter to the drivers' tx method. Signed-off-by: Thomas Huehn Signed-off-by: Alina Friedrichsen Signed-off-by: Felix Fietkau [reworded commit message] Signed-off-by: Johannes Berg --- net/mac80211/driver-ops.h | 6 ++++-- net/mac80211/tx.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index df9203199102..a81117a83996 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -22,9 +22,11 @@ get_bss_sdata(struct ieee80211_sub_if_data *sdata) return sdata; } -static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) +static inline void drv_tx(struct ieee80211_local *local, + struct ieee80211_tx_control *control, + struct sk_buff *skb) { - local->ops->tx(&local->hw, skb); + local->ops->tx(&local->hw, control, skb); } static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index acf712ffb5e6..7558ba58ea23 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1204,6 +1204,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, struct sk_buff_head *skbs, bool txpending) { + struct ieee80211_tx_control control; struct sk_buff *skb, *tmp; unsigned long flags; @@ -1240,10 +1241,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); info->control.vif = vif; - info->control.sta = sta; + control.sta = sta; __skb_unlink(skb, skbs); - drv_tx(local, skb); + drv_tx(local, &control, skb); } return true; -- cgit v1.2.1 From 1b49de26566e7175e8f2d0934db6d9119f553b56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2012 10:29:14 +0200 Subject: mac80211: supress HT/VHT disable if not supported If HT/VHT isn't supported by us we shouldn't print a message that we disabled it, do that only if the AP didn't support WMM and we therefore disable it. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ea46c6446450..c8465478b4b0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3373,16 +3373,18 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (!sband->ht_cap.ht_supported || local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; - netdev_info(sdata->dev, - "disabling HT as WMM/QoS is not supported\n"); + if (!bss->wmm_used) + netdev_info(sdata->dev, + "disabling HT as WMM/QoS is not supported by the AP\n"); } /* disable VHT if we don't support it or the AP doesn't use WMM */ if (!sband->vht_cap.vht_supported || local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; - netdev_info(sdata->dev, - "disabling VHT as WMM/QoS is not supported\n"); + if (!bss->wmm_used) + netdev_info(sdata->dev, + "disabling VHT as WMM/QoS is not supported by the AP\n"); } memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); -- cgit v1.2.1 From 13e0c8e355983cdd4ea7accc3b3208e80944716d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2012 10:43:16 +0200 Subject: mac80211: rename sta to new_sta In ieee80211_prep_connection(), the station (if not NULL) is the new station (representing the AP) that needs to be added. Rename the variable to "new_sta" to clarify this. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c8465478b4b0..e065ef5f7b2f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3044,7 +3044,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)cbss->priv; - struct sta_info *sta = NULL; + struct sta_info *new_sta = NULL; bool have_sta = false; int err; int ht_cfreq; @@ -3063,8 +3063,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (!have_sta) { - sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); - if (!sta) + new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); + if (!new_sta) return -ENOMEM; } @@ -3135,7 +3135,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, local->oper_channel = cbss->channel; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - if (sta) { + if (new_sta) { u32 rates = 0, basic_rates = 0; bool have_higher_than_11mbit; int min_rate = INT_MAX, min_rate_index = -1; @@ -3160,7 +3160,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, basic_rates = BIT(min_rate_index); } - sta->sta.supp_rates[cbss->channel->band] = rates; + new_sta->sta.supp_rates[cbss->channel->band] = rates; sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ @@ -3183,10 +3183,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, BSS_CHANGED_BEACON_INT); if (assoc) - sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH); - err = sta_info_insert(sta); - sta = NULL; + err = sta_info_insert(new_sta); + new_sta = NULL; if (err) { sdata_info(sdata, "failed to insert STA entry for the AP (error %d)\n", -- cgit v1.2.1 From b17166a707e748ad87907f38431a1df26bb643f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2012 11:41:27 +0200 Subject: mac80211: set channel only once during auth/assoc There's no need to set up the channel during auth and again during assoc, just do it once. Currently this doesn't result in any changes since calling hw_config() with an unchanged channel will return early, but with the channel context work this has an impact on channel context assignment. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 69 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 26 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e065ef5f7b2f..682055207588 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3038,41 +3038,17 @@ int ieee80211_max_network_latency(struct notifier_block *nb, return 0; } -static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, bool assoc) +static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss *bss = (void *)cbss->priv; - struct sta_info *new_sta = NULL; - bool have_sta = false; - int err; int ht_cfreq; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; const u8 *ht_oper_ie; const struct ieee80211_ht_operation *ht_oper = NULL; struct ieee80211_supported_band *sband; - if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) - return -EINVAL; - - if (assoc) { - rcu_read_lock(); - have_sta = sta_info_get(sdata, cbss->bssid); - rcu_read_unlock(); - } - - if (!have_sta) { - new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); - if (!new_sta) - return -ENOMEM; - } - - mutex_lock(&local->mtx); - ieee80211_recalc_idle(sdata->local); - mutex_unlock(&local->mtx); - - /* switch to the right channel */ sband = local->hw.wiphy->bands[cbss->channel->band]; ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; @@ -3135,10 +3111,51 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, local->oper_channel = cbss->channel; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + return 0; +} + +static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss, bool assoc) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_bss *bss = (void *)cbss->priv; + struct sta_info *new_sta = NULL; + bool have_sta = false; + int err; + + if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) + return -EINVAL; + + if (assoc) { + rcu_read_lock(); + have_sta = sta_info_get(sdata, cbss->bssid); + rcu_read_unlock(); + } + + if (!have_sta) { + new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); + if (!new_sta) + return -ENOMEM; + } + + mutex_lock(&local->mtx); + ieee80211_recalc_idle(sdata->local); + mutex_unlock(&local->mtx); + if (new_sta) { u32 rates = 0, basic_rates = 0; bool have_higher_than_11mbit; int min_rate = INT_MAX, min_rate_index = -1; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[cbss->channel->band]; + + err = ieee80211_prep_channel(sdata, cbss); + if (err) { + sta_info_free(local, new_sta); + return err; + } ieee80211_get_rates(sband, bss->supp_rates, bss->supp_rates_len, -- cgit v1.2.1 From 6962d602056c88ce470f991a265a33132fb95232 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:29:21 +0200 Subject: mac80211: use oper_channel in mesh Using hw.conf.channel is wrong as it could be the temporary channel if any function like the beacon get function is called while scanning or during other temporary out-of-channel activities. Use oper_channel instead. Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6fac18c0423f..03f1696d7d98 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -349,17 +349,18 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan = local->oper_channel; u8 *pos; if (skb_tailroom(skb) < 3) return -ENOMEM; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[chan->band]; if (sband->band == IEEE80211_BAND_2GHZ) { pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); + *pos++ = ieee80211_frequency_to_channel(chan->center_freq); } return 0; @@ -603,7 +604,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sdata->local, - sdata->local->hw.conf.channel->band); + sdata->local->oper_channel->band); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_HT | -- cgit v1.2.1 From 273686d664daae1aa728b76e45720273b26dd876 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:29:21 +0200 Subject: mac80211: use oper_channel in ibss Using hw.conf.channel is wrong as it could be the temporary channel if any function like the beacon get function is called while scanning or during other temporary out-of-channel activities. Use oper_channel instead. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5746d62faba1..d06208518eae 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -205,7 +205,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mod_timer(&ifibss->timer, round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, + bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, mgmt, skb->len, 0, GFP_KERNEL); cfg80211_put_bss(bss); netif_carrier_on(sdata->dev); @@ -294,7 +294,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - int band = local->hw.conf.channel->band; + int band = local->oper_channel->band; /* * XXX: Consider removing the least recently used entry and @@ -561,7 +561,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - int band = local->hw.conf.channel->band; + int band = local->oper_channel->band; /* * XXX: Consider removing the least recently used entry and @@ -759,7 +759,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) return; } sdata_info(sdata, "IBSS not allowed on %d MHz\n", - local->hw.conf.channel->center_freq); + local->oper_channel->center_freq); /* No IBSS found - decrease scan interval and continue * scanning. */ -- cgit v1.2.1 From 568d6e289736c9c78cd8723aa81415daffafeff9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:29:21 +0200 Subject: mac80211: use oper_channel in managed mlme Using hw.conf.channel is wrong as it could be the temporary channel if any function like the beacon get function is called while scanning or during other temporary out-of-channel activities. Use oper_channel instead. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 682055207588..2657a5645a8a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -185,15 +185,15 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, u16 ht_opmode; bool disable_40 = false; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[local->oper_channel->band]; switch (sdata->vif.bss_conf.channel_type) { case NL80211_CHAN_HT40PLUS: - if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS) + if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) disable_40 = true; break; case NL80211_CHAN_HT40MINUS: - if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS) + if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) disable_40 = true; break; default: @@ -1274,7 +1274,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); - if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) use_short_slot = true; if (use_protection != bss_conf->use_cts_prot) { @@ -2364,7 +2364,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (baselen > len) return; - if (rx_status->freq != local->hw.conf.channel->center_freq) + if (rx_status->freq != local->oper_channel->center_freq) return; if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && @@ -2528,7 +2528,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[local->oper_channel->band]; changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, bssid, true); -- cgit v1.2.1 From 679ef4eadde1f8e55074427c0d8de2da55ca81f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:29:21 +0200 Subject: mac80211: use oper_channel in utils and config Using hw.conf.channel is wrong as it could be the temporary channel if any function like the beacon get function is called while scanning or during other temporary out-of-channel activities. Use oper_channel instead. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 6 +++--- net/mac80211/iface.c | 2 +- net/mac80211/util.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 06b8d39780e9..1b8d19112943 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -330,7 +330,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { struct ieee80211_supported_band *sband; sband = sta->local->hw.wiphy->bands[ - sta->local->hw.conf.channel->band]; + sta->local->oper_channel->band]; rate->legacy = sband->bitrates[idx].bitrate; } else rate->mcs = idx; @@ -1662,7 +1662,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, } if (!sdata->vif.bss_conf.use_short_slot && - sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { + sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) { sdata->vif.bss_conf.use_short_slot = true; changed |= BSS_CHANGED_ERP_SLOT; } @@ -1928,7 +1928,7 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_channel *chan = local->hw.conf.channel; + struct ieee80211_channel *chan = local->oper_channel; u32 changes = 0; switch (type) { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bfb57dcc1538..fc8ba83e2c33 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1274,7 +1274,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, /* reset some values that shouldn't be kept across type changes */ sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sdata->local, - sdata->local->hw.conf.channel->band); + sdata->local->oper_channel->band); sdata->drop_unencrypted = 0; if (type == NL80211_IFTYPE_STATION) sdata->u.mgd.use_4addr = false; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 037d148e9f19..39005eca1a59 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -832,7 +832,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, memset(&qparam, 0, sizeof(qparam)); - use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && + use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); /* @@ -919,7 +919,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, if ((supp_rates[i] & 0x7f) * 5 > 110) have_higher_than_11mbit = 1; - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + if (local->oper_channel->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else -- cgit v1.2.1 From 6b77863b719a4e32909c218c0d5a83a14f4d98c5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:53:27 +0200 Subject: mac80211: fix current vs. operating channel in preq/beacon When sending probe requests, e.g. during software scanning, these will go out on the *current* channel, so their IEs need to be built from the current channel. At other times, e.g. for beacons or probe request templates, the IEs will be used on the *operating* channel and using the current channel instead might result in errors. Add the appropriate parameters to respect the difference. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 20 ++++++++++++++------ net/mac80211/ieee80211_i.h | 7 +++++-- net/mac80211/mesh_plink.c | 6 ++++-- net/mac80211/mlme.c | 4 +++- net/mac80211/tx.c | 6 +++--- net/mac80211/util.c | 27 +++++++++++++++------------ 6 files changed, 44 insertions(+), 26 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1b8d19112943..5583f5b73dc9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2655,6 +2655,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct ieee80211_tdls_data *tf; tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); @@ -2674,8 +2675,10 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_req.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false); - ieee80211_add_ext_srates_ie(sdata, skb, false); + ieee80211_add_srates_ie(sdata, skb, false, + local->oper_channel->band); + ieee80211_add_ext_srates_ie(sdata, skb, false, + local->oper_channel->band); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_RESPONSE: @@ -2688,8 +2691,10 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false); - ieee80211_add_ext_srates_ie(sdata, skb, false); + ieee80211_add_srates_ie(sdata, skb, false, + local->oper_channel->band); + ieee80211_add_ext_srates_ie(sdata, skb, false, + local->oper_channel->band); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_CONFIRM: @@ -2727,6 +2732,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; mgmt = (void *)skb_put(skb, 24); @@ -2749,8 +2755,10 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(sdata, skb, false); - ieee80211_add_ext_srates_ie(sdata, skb, false); + ieee80211_add_srates_ie(sdata, skb, false, + local->oper_channel->band); + ieee80211_add_ext_srates_ie(sdata, skb, false, + local->oper_channel->band); ieee80211_tdls_add_ext_capab(skb); break; default: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8e65ad9c870a..0aaad023cdbe 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1459,6 +1459,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, u8 channel); struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, u32 ratemask, + struct ieee80211_channel *chan, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, bool directed); @@ -1489,9 +1490,11 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u32 cap); int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic); + struct sk_buff *skb, bool need_basic, + enum ieee80211_band band); int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic); + struct sk_buff *skb, bool need_basic, + enum ieee80211_band band); /* channel management */ enum ieee80211_chan_mode { diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fa642c794719..985b37f7455d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -258,8 +258,10 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2); memcpy(pos + 2, &plid, 2); } - if (ieee80211_add_srates_ie(sdata, skb, true) || - ieee80211_add_ext_srates_ie(sdata, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true, + local->oper_channel->band) || + ieee80211_add_ext_srates_ie(sdata, skb, true, + local->oper_channel->band) || mesh_add_rsn_ie(skb, sdata) || mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2657a5645a8a..c416a08d90f1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1683,7 +1683,9 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ssid_len = ssid[1]; skb = ieee80211_build_probe_req(sdata, cbss->bssid, - (u32) -1, ssid + 2, ssid_len, + (u32) -1, + sdata->local->oper_channel, + ssid + 2, ssid_len, NULL, 0, true); return skb; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7558ba58ea23..b559c6bd8681 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2303,7 +2303,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_if_ap *ap = NULL; struct beacon_data *beacon; struct ieee80211_supported_band *sband; - enum ieee80211_band band = local->hw.conf.channel->band; + enum ieee80211_band band = local->oper_channel->band; struct ieee80211_tx_rate_control txrc; sband = local->hw.wiphy->bands[band]; @@ -2429,9 +2429,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *pos++ = WLAN_EID_SSID; *pos++ = 0x0; - if (ieee80211_add_srates_ie(sdata, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true, band) || mesh_add_ds_params_ie(skb, sdata) || - ieee80211_add_ext_srates_ie(sdata, skb, true) || + ieee80211_add_ext_srates_ie(sdata, skb, true, band) || mesh_add_rsn_ie(skb, sdata) || mesh_add_ht_cap_ie(skb, sdata) || mesh_add_ht_oper_ie(skb, sdata) || diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 39005eca1a59..99e4258bdb26 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1100,6 +1100,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, u32 ratemask, + struct ieee80211_channel *chan, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, bool directed) @@ -1109,7 +1110,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; size_t buf_len; u8 *buf; - u8 chan; + u8 chan_no; /* FIXME: come up with a proper value */ buf = kmalloc(200 + ie_len, GFP_KERNEL); @@ -1122,14 +1123,12 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, * badly-behaved APs don't respond when this parameter is included. */ if (directed) - chan = 0; + chan_no = 0; else - chan = ieee80211_frequency_to_channel( - local->hw.conf.channel->center_freq); + chan_no = ieee80211_frequency_to_channel(chan->center_freq); - buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, - local->hw.conf.channel->band, - ratemask, chan); + buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, + ratemask, chan_no); skb = ieee80211_probereq_get(&local->hw, &sdata->vif, ssid, ssid_len, @@ -1158,7 +1157,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, { struct sk_buff *skb; - skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, + skb = ieee80211_build_probe_req(sdata, dst, ratemask, + sdata->local->hw.conf.channel, + ssid, ssid_len, ie, ie_len, directed); if (skb) { if (no_cck) @@ -1810,7 +1811,8 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) } int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic) + struct sk_buff *skb, bool need_basic, + enum ieee80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; @@ -1818,7 +1820,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, u8 i, rates, *pos; u32 basic_rates = sdata->vif.bss_conf.basic_rates; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; rates = sband->n_bitrates; if (rates > 8) rates = 8; @@ -1841,7 +1843,8 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, } int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, bool need_basic) + struct sk_buff *skb, bool need_basic, + enum ieee80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; @@ -1849,7 +1852,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, u8 i, exrates, *pos; u32 basic_rates = sdata->vif.bss_conf.basic_rates; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; exrates = sband->n_bitrates; if (exrates > 8) exrates -= 8; -- cgit v1.2.1 From 2d56577bc68e56097a1cd6599b678e8cab758e64 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 15:12:51 +0200 Subject: mac80211: use correct channel in TX Since we only need the band, remove the channel pointer from struct ieee80211_tx_data and also assign it properly, depending on context, to the correct operating or current channel. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/tx.c | 17 +++++++---------- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0aaad023cdbe..d1a7c58a8c62 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -193,8 +193,6 @@ struct ieee80211_tx_data { struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_channel *channel; - unsigned int flags; }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b559c6bd8681..5b81660a35b3 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -55,7 +55,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) return 0; - sband = local->hw.wiphy->bands[tx->channel->band]; + sband = local->hw.wiphy->bands[info->band]; txrate = &sband->bitrates[info->control.rates[0].idx]; erp = txrate->flags & IEEE80211_RATE_ERP_G; @@ -615,7 +615,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) memset(&txrc, 0, sizeof(txrc)); - sband = tx->local->hw.wiphy->bands[tx->channel->band]; + sband = tx->local->hw.wiphy->bands[info->band]; len = min_t(u32, tx->skb->len + FCS_LEN, tx->local->hw.wiphy->frag_threshold); @@ -626,13 +626,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.bss_conf = &tx->sdata->vif.bss_conf; txrc.skb = tx->skb; txrc.reported_rate.idx = -1; - txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; + txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band]; if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; memcpy(txrc.rate_idx_mcs_mask, - tx->sdata->rc_rateidx_mcs_mask[tx->channel->band], + tx->sdata->rc_rateidx_mcs_mask[info->band], sizeof(txrc.rate_idx_mcs_mask)); txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || @@ -667,7 +667,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) "scanning and associated. Target station: " "%pM on %d GHz band\n", tx->sdata->name, hdr->addr1, - tx->channel->band ? 5 : 2)) + info->band ? 5 : 2)) return TX_DROP; /* @@ -1131,7 +1131,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, tx->skb = skb; tx->local = local; tx->sdata = sdata; - tx->channel = local->hw.conf.channel; __skb_queue_head_init(&tx->skbs); /* @@ -1400,8 +1399,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, goto out; } - tx.channel = local->hw.conf.channel; - info->band = tx.channel->band; + info->band = local->hw.conf.channel->band; /* set up hw_queue value early */ if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || @@ -2710,8 +2708,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); tx.flags |= IEEE80211_TX_PS_BUFFERED; - tx.channel = local->hw.conf.channel; - info->band = tx.channel->band; + info->band = local->oper_channel->band; if (invoke_tx_handlers(&tx)) skb = NULL; -- cgit v1.2.1 From c405c6298eacd423098afacf6020ddbda1b0378b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Jul 2012 19:44:12 +0200 Subject: mac80211: manage carrier state in mesh Instead of assuming the carrier is on all the time in mesh manage it with joining and leaving the mesh. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 12 ++++++++---- net/mac80211/mesh.c | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fc8ba83e2c33..c65a03ba809f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -539,12 +539,16 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) changed |= ieee80211_reset_erp_info(sdata); ieee80211_bss_info_change_notify(sdata, changed); - if (sdata->vif.type == NL80211_IFTYPE_STATION || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_AP) + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: netif_carrier_off(dev); - else + break; + default: netif_carrier_on(dev); + } /* * set default queue parameters so drivers don't diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 03f1696d7d98..571d5183060e 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -610,6 +610,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_HT | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT); + + netif_carrier_on(sdata->dev); } void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) @@ -617,6 +619,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + netif_carrier_off(sdata->dev); + ifmsh->mesh_id_len = 0; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); sta_info_flush(local, NULL); -- cgit v1.2.1 From 1411af156524ce42c2a7f989320c4484257f3ff5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Jul 2012 19:48:09 +0200 Subject: mac80211: enable WDS carrier only after adding station Enable the carrier on WDS type interfaces only after having added the station entry for the WDS peer so outgoing frames will find it. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c65a03ba809f..2d6ac78971ea 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -546,6 +546,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) case NL80211_IFTYPE_MESH_POINT: netif_carrier_off(dev); break; + case NL80211_IFTYPE_WDS: + break; default: netif_carrier_on(dev); } @@ -580,6 +582,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) } rate_control_rate_init(sta); + netif_carrier_on(dev); } /* -- cgit v1.2.1 From e83e6541cee0a12bc445b0f4fad5214df5803087 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Jul 2012 16:23:07 +0200 Subject: mac80211: use eth_broadcast_addr Instead of memset(). Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/ibss.c | 2 +- net/mac80211/mesh_pathtbl.c | 2 +- net/mac80211/tx.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5583f5b73dc9..df64b455821d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -950,7 +950,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - memset(msg->da, 0xff, ETH_ALEN); + eth_broadcast_addr(msg->da); memcpy(msg->sa, sta->sta.addr, ETH_ALEN); msg->len = htons(6); msg->dsap = 0; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index d06208518eae..1ebda2f9e57b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -109,7 +109,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); - memset(mgmt->da, 0xff, ETH_ALEN); + eth_broadcast_addr(mgmt->da); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 075bc535c601..bec7b281b5ba 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -531,7 +531,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) read_lock_bh(&pathtbl_resize_lock); memcpy(new_mpath->dst, dst, ETH_ALEN); - memset(new_mpath->rann_snd_addr, 0xff, ETH_ALEN); + eth_broadcast_addr(new_mpath->rann_snd_addr); new_mpath->is_root = false; new_mpath->sdata = sdata; new_mpath->flags = 0; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5b81660a35b3..7dbcf293708b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2415,7 +2415,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, memset(mgmt, 0, hdr_len); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); + eth_broadcast_addr(mgmt->da); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); mgmt->u.beacon.beacon_int = @@ -2609,9 +2609,9 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, memset(hdr, 0, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); - memset(hdr->addr1, 0xff, ETH_ALEN); + eth_broadcast_addr(hdr->addr1); memcpy(hdr->addr2, vif->addr, ETH_ALEN); - memset(hdr->addr3, 0xff, ETH_ALEN); + eth_broadcast_addr(hdr->addr3); pos = skb_put(skb, ie_ssid_len); *pos++ = WLAN_EID_SSID; -- cgit v1.2.1 From 19c3b8303d4686aa373c669ee833609b3fb403cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 20:13:36 +0200 Subject: mac80211: reset station MLME flags upon new association When associating anew, the old station MLME flags should be cleared. The only exception is the 40 MHz disable flag as it might have been set while the channel was set in a previous authentication attempt so it needs to be kept intact. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c416a08d90f1..9d60b4993635 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3357,10 +3357,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } /* prepare assoc data */ - - ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; - ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; - ifmgd->flags &= ~IEEE80211_STA_DISABLE_VHT; + + /* + * keep only the 40 MHz disable bit set as it might have + * been set during authentication already, all other bits + * should be reset for a new connection + */ + ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; ifmgd->beacon_crc_valid = false; -- cgit v1.2.1 From 0d466b9c6798d431141ab15ae6d5ea413b4d09b2 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 3 Aug 2012 12:21:32 -0700 Subject: mac80211: improve cleanup when leaving mesh It is not necessary to stop the mesh beacon in the mac80211 ndo_stop handler, since cfg80211 has already left the mesh on NETDEV_GOING_DOWN notification. Also some improvements to ieee80211_stop_mesh(): - flush mpath entries. - flush sta entries per-sdata so we don't remove entries belonging to other vifs on the same hw. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 8 -------- net/mac80211/mesh.c | 6 +++++- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2d6ac78971ea..5a81577879ed 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -777,14 +777,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, synchronize_rcu(); skb_queue_purge(&sdata->skb_queue); - /* - * Disable beaconing here for mesh only, AP and IBSS - * are already taken care of. - */ - if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_ENABLED); - /* * Free all remaining keys, there shouldn't be any, * except maybe group keys in AP more or WDS? diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 571d5183060e..035cd0c8ce33 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -621,9 +621,13 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); + /* stop the beacon */ ifmsh->mesh_id_len = 0; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); - sta_info_flush(local, NULL); + + /* flush STAs and mpaths on this iface */ + sta_info_flush(sdata->local, sdata); + mesh_path_flush_by_iface(sdata); del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); -- cgit v1.2.1 From 3e17f2be31f354fe03e1732bc527a31ff3dd3bb9 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 3 Aug 2012 12:21:33 -0700 Subject: mac80211: remove ieee80211_clean_sdata() This function was only used by mesh, and not really needed since any interface-specific cleanup already happens in the netdev handlers. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5a81577879ed..abee3a0c25ed 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1155,18 +1155,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, ieee80211_debugfs_add_netdev(sdata); } -static void ieee80211_clean_sdata(struct ieee80211_sub_if_data *sdata) -{ - switch (sdata->vif.type) { - case NL80211_IFTYPE_MESH_POINT: - mesh_path_flush_by_iface(sdata); - break; - - default: - break; - } -} - static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type) { @@ -1502,9 +1490,6 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) list_del_rcu(&sdata->list); mutex_unlock(&sdata->local->iflist_mtx); - /* clean up type-dependent data */ - ieee80211_clean_sdata(sdata); - synchronize_rcu(); unregister_netdevice(sdata->dev); } @@ -1524,8 +1509,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_del(&sdata->list); - ieee80211_clean_sdata(sdata); - unregister_netdevice_queue(sdata->dev, &unreg_list); } mutex_unlock(&local->iflist_mtx); -- cgit v1.2.1 From e7570dfb635b0c89570852002c9f85dd1cf82ba1 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 3 Aug 2012 12:21:34 -0700 Subject: mac80211: don't request ack for peering close It doesn't make a lot of sense to wait for an ack in response to a peering close frame since either peer in this exchange could be going down. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 985b37f7455d..bad5126c8483 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -217,6 +217,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, u8 *da, __le16 llid, __le16 plid, __le16 reason) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; + struct ieee80211_tx_info *info; struct ieee80211_mgmt *mgmt; bool include_plid = false; u16 peering_proto = 0; @@ -238,6 +239,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, sdata->u.mesh.ie_len); if (!skb) return -1; + info = IEEE80211_SKB_CB(skb); skb_reserve(skb, local->tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); memset(mgmt, 0, hdr_len); @@ -267,6 +269,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mesh_add_meshconf_ie(skb, sdata)) return -1; } else { /* WLAN_SP_MESH_PEERING_CLOSE */ + info->flags |= IEEE80211_TX_CTL_NO_ACK; if (mesh_add_meshid_ie(skb, sdata)) return -1; } -- cgit v1.2.1 From f609a43dca2964a8a604ef554be92fa11c3b4c41 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 3 Aug 2012 12:21:35 -0700 Subject: mac80211: skb leak in mesh_plink_frame_tx() Although adding an IE is almost guaranteed to succeed since we already accounted for its length while allocating the skb, we should still free the skb in case of failure. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index bad5126c8483..5fd1250f7866 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -224,6 +224,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, u8 *pos, ie_len = 4; int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) + sizeof(mgmt->u.action.u.self_prot); + int err = -ENOMEM; skb = dev_alloc_skb(local->tx_headroom + hdr_len + @@ -267,11 +268,11 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mesh_add_rsn_ie(skb, sdata) || mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) - return -1; + goto free; } else { /* WLAN_SP_MESH_PEERING_CLOSE */ info->flags |= IEEE80211_TX_CTL_NO_ACK; if (mesh_add_meshid_ie(skb, sdata)) - return -1; + goto free; } /* Add Mesh Peering Management element */ @@ -290,11 +291,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ie_len += 2; /* reason code */ break; default: - return -EINVAL; + err = -EINVAL; + goto free; } if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) - return -ENOMEM; + goto free; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PEER_MGMT; @@ -315,14 +317,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, if (action != WLAN_SP_MESH_PEERING_CLOSE) { if (mesh_add_ht_cap_ie(skb, sdata) || mesh_add_ht_oper_ie(skb, sdata)) - return -1; + goto free; } if (mesh_add_vendor_ies(skb, sdata)) - return -1; + goto free; ieee80211_tx_skb(sdata, skb); return 0; +free: + kfree_skb(skb); + return err; } /** -- cgit v1.2.1 From df32381896f5f0c78a371df2e49ab7c776b1a5ba Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Wed, 8 Aug 2012 07:58:43 +0200 Subject: mac80211: fix unnecessary beacon update after peering status change ieee80211_bss_info_change_notify is called everytime a peer link is established or closed, because the accepting_plinks flag in the meshconf IE *might* have changed. With this patch the corresponding functions return the BSS_CHANGED_BEACON flag when a beacon update is necessary. Also it makes mesh_accept_plinks_update the common place to update the accepting_plinks flag. mesh_accept_plinks_update is called upon plink change and also periodically from ieee80211_mesh_housekeeping. Thus, it also picks up changes of local->num_sta. Signed-off-by: Marco Porsch Acked-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 21 +++++++++++++-------- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_plink.c | 44 +++++++++++++++++++------------------------- 3 files changed, 33 insertions(+), 34 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6fac18c0423f..856dcf49ce75 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -136,10 +136,13 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) * mesh_accept_plinks_update - update accepting_plink in local mesh beacons * * @sdata: mesh interface in which mesh beacons are going to be updated + * + * Returns: beacon changed flag if the beacon content changed. */ -void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) +u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) { bool free_plinks; + u32 changed = 0; /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, * the mesh interface might be able to establish plinks with peers that @@ -149,8 +152,12 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) */ free_plinks = mesh_plink_availables(sdata); - if (free_plinks != sdata->u.mesh.accepting_plinks) - ieee80211_mesh_housekeeping_timer((unsigned long) sdata); + if (free_plinks != sdata->u.mesh.accepting_plinks) { + sdata->u.mesh.accepting_plinks = free_plinks; + changed = BSS_CHANGED_BEACON; + } + + return changed; } int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) @@ -262,7 +269,6 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) neighbors = (neighbors > 15) ? 15 : neighbors; *pos++ = neighbors << 1; /* Mesh capability */ - ifmsh->accepting_plinks = mesh_plink_availables(sdata); *pos = MESHCONF_CAPAB_FORWARDING; *pos |= ifmsh->accepting_plinks ? MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; @@ -521,14 +527,13 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh) { - bool free_plinks; + u32 changed; ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); mesh_path_expire(sdata); - free_plinks = mesh_plink_availables(sdata); - if (free_plinks != sdata->u.mesh.accepting_plinks) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); + changed = mesh_accept_plinks_update(sdata); + ieee80211_bss_info_change_notify(sdata, changed); mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index faaa39bcfd10..13fd5b5fdb0a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -282,7 +282,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, u8 *hw_addr, struct ieee802_11_elems *ie); bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); -void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); +u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); void mesh_plink_broken(struct sta_info *sta); void mesh_plink_deactivate(struct sta_info *sta); int mesh_plink_open(struct sta_info *sta); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index af671b984df3..f20e9f26d137 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -48,17 +48,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, u8 *da, __le16 llid, __le16 plid, __le16 reason); static inline -void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) +u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); - mesh_accept_plinks_update(sdata); + return mesh_accept_plinks_update(sdata); } static inline -void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) +u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); - mesh_accept_plinks_update(sdata); + return mesh_accept_plinks_update(sdata); } /** @@ -170,22 +170,21 @@ out: * @sta: mesh peer link to deactivate * * All mesh paths with this peer as next hop will be flushed + * Returns beacon changed flag if the beacon content changed. * * Locking: the caller must hold sta->lock */ -static bool __mesh_plink_deactivate(struct sta_info *sta) +static u32 __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - bool deactivated = false; + u32 changed = 0; - if (sta->plink_state == NL80211_PLINK_ESTAB) { - mesh_plink_dec_estab_count(sdata); - deactivated = true; - } + if (sta->plink_state == NL80211_PLINK_ESTAB) + changed = mesh_plink_dec_estab_count(sdata); sta->plink_state = NL80211_PLINK_BLOCKED; mesh_path_flush_by_nexthop(sta); - return deactivated; + return changed; } /** @@ -198,18 +197,17 @@ static bool __mesh_plink_deactivate(struct sta_info *sta) void mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - bool deactivated; + u32 changed; spin_lock_bh(&sta->lock); - deactivated = __mesh_plink_deactivate(sta); + changed = __mesh_plink_deactivate(sta); sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, sta->llid, sta->plid, sta->reason); spin_unlock_bh(&sta->lock); - if (deactivated) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); + ieee80211_bss_info_change_notify(sdata, changed); } static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, @@ -541,15 +539,14 @@ int mesh_plink_open(struct sta_info *sta) void mesh_plink_block(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - bool deactivated; + u32 changed; spin_lock_bh(&sta->lock); - deactivated = __mesh_plink_deactivate(sta); + changed = __mesh_plink_deactivate(sta); sta->plink_state = NL80211_PLINK_BLOCKED; spin_unlock_bh(&sta->lock); - if (deactivated) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); + ieee80211_bss_info_change_notify(sdata, changed); } @@ -852,9 +849,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m del_timer(&sta->plink_timer); sta->plink_state = NL80211_PLINK_ESTAB; spin_unlock_bh(&sta->lock); - mesh_plink_inc_estab_count(sdata); + changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); - changed |= BSS_CHANGED_BEACON; mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); break; @@ -888,9 +884,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m del_timer(&sta->plink_timer); sta->plink_state = NL80211_PLINK_ESTAB; spin_unlock_bh(&sta->lock); - mesh_plink_inc_estab_count(sdata); + changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); - changed |= BSS_CHANGED_BEACON; mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); mesh_plink_frame_tx(sdata, @@ -908,13 +903,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m case CLS_ACPT: reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); sta->reason = reason; - __mesh_plink_deactivate(sta); + changed |= __mesh_plink_deactivate(sta); sta->plink_state = NL80211_PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); changed |= mesh_set_ht_prot_mode(sdata); - changed |= BSS_CHANGED_BEACON; mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, llid, plid, reason); break; -- cgit v1.2.1 From aa7a00809cf6afe3cd6f5af2889110b47b798667 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 6 Aug 2012 14:26:16 +0300 Subject: mac80211: avoid using synchronize_rcu in ieee80211_set_probe_resp This could take a while (100ms+) and may delay sending assoc resp in AP mode with WPS or P2P GO (as setting the probe resp takes place there). We've encountered situations where the delay was big enough to cause connection problems with devices like Galaxy Nexus. Switch to using call_rcu with a free handler. [Arik - rework to use plain buffer and instead of skb] Signed-off-by: Eyal Shapira Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 16 +++++++--------- net/mac80211/ieee80211_i.h | 8 +++++++- net/mac80211/iface.c | 4 ++-- net/mac80211/tx.c | 7 +++++-- 4 files changed, 21 insertions(+), 14 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index df64b455821d..8052a7ad03a6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -725,25 +725,23 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, const u8 *resp, size_t resp_len) { - struct sk_buff *new, *old; + struct probe_resp *new, *old; if (!resp || !resp_len) - return 1; + return -EINVAL; old = rtnl_dereference(sdata->u.ap.probe_resp); - new = dev_alloc_skb(resp_len); + new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); if (!new) return -ENOMEM; - memcpy(skb_put(new, resp_len), resp, resp_len); + new->len = resp_len; + memcpy(new->data, resp, resp_len); rcu_assign_pointer(sdata->u.ap.probe_resp, new); - if (old) { - /* TODO: use call_rcu() */ - synchronize_rcu(); - dev_kfree_skb(old); - } + if (old) + kfree_rcu(old, rcu_head); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d1a7c58a8c62..e22aee83ba53 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -272,9 +272,15 @@ struct beacon_data { struct rcu_head rcu_head; }; +struct probe_resp { + struct rcu_head rcu_head; + int len; + u8 data[0]; +}; + struct ieee80211_if_ap { struct beacon_data __rcu *beacon; - struct sk_buff __rcu *probe_resp; + struct probe_resp __rcu *probe_resp; struct list_head vlans; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index abee3a0c25ed..fbab7a84ca21 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -715,7 +715,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *vlan, *tmpsdata; struct beacon_data *old_beacon = rtnl_dereference(sdata->u.ap.beacon); - struct sk_buff *old_probe_resp = + struct probe_resp *old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); /* sdata_running will return false, so this will disable */ @@ -727,7 +727,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); synchronize_rcu(); kfree(old_beacon); - kfree_skb(old_probe_resp); + kfree(old_probe_resp); /* down all dependent devices, that is VLANs */ list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7dbcf293708b..2d004ba0615e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2481,7 +2481,8 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ieee80211_if_ap *ap = NULL; - struct sk_buff *presp = NULL, *skb = NULL; + struct sk_buff *skb = NULL; + struct probe_resp *presp = NULL; struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -2495,10 +2496,12 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, if (!presp) goto out; - skb = skb_copy(presp, GFP_ATOMIC); + skb = dev_alloc_skb(presp->len); if (!skb) goto out; + memcpy(skb_put(skb, presp->len), presp->data, presp->len); + hdr = (struct ieee80211_hdr *) skb->data; memset(hdr->addr1, 0, sizeof(hdr->addr1)); -- cgit v1.2.1 From b22bd5221cfe80ee3d345d9deccfd29edf9bafb4 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 9 Aug 2012 18:15:39 -0700 Subject: mac80211: use skb_queue_walk() in mesh_path_assign_nexthop Since all we really want is just to iterate over all skbs, do just that and avoid (de)queueing to a clusmy tmpq. Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh_pathtbl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index bec7b281b5ba..b819d6b847d0 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -203,23 +203,17 @@ 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) { + skb_queue_walk(&mpath->frame_queue, skb) { hdr = (struct ieee80211_hdr *) skb->data; memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); - __skb_queue_tail(&tmpq, skb); } - skb_queue_splice(&tmpq, &mpath->frame_queue); spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); } -- cgit v1.2.1 From 4bd4c2dd8e734868ae9f0ceb87a6edd27df8f45c Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 9 Aug 2012 18:15:40 -0700 Subject: mac80211: clean up mpath_move_to_queue() Use skb_queue_walk_safe instead, and fix a few issues: - didn't free old skbs on moving - didn't react to failed skb alloc - needlessly held a local pointer to the destination frame queue - didn't check destination queue length before adding skb Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg --- net/mac80211/mesh.h | 3 +++ net/mac80211/mesh_hwmp.c | 2 -- net/mac80211/mesh_pathtbl.c | 34 ++++++++++++++++++---------------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index faaa39bcfd10..e4d911ffd5d1 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -215,6 +215,9 @@ struct mesh_rmc { /* Maximum number of paths per interface */ #define MESH_MAX_MPATHS 1024 +/* Number of frames buffered per destination for unresolved destinations */ +#define MESH_FRAME_QUEUE_LEN 10 + /* Public interfaces */ /* Various */ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 494bc39f61a4..47aeee2d8db1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -17,8 +17,6 @@ #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 -/* Number of frames buffered per destination for unresolved destinations */ -#define MESH_FRAME_QUEUE_LEN 10 #define MAX_PREQ_QUEUE_LEN 64 /* Destination only */ diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index b819d6b847d0..aa749818860e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -279,40 +279,42 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, struct mesh_path *from_mpath, bool copy) { - struct sk_buff *skb, *cp_skb = NULL; - struct sk_buff_head gateq, failq; + struct sk_buff *skb, *fskb, *tmp; + struct sk_buff_head failq; unsigned long flags; - int num_skbs; BUG_ON(gate_mpath == from_mpath); BUG_ON(!gate_mpath->next_hop); - __skb_queue_head_init(&gateq); __skb_queue_head_init(&failq); spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); skb_queue_splice_init(&from_mpath->frame_queue, &failq); spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); - num_skbs = skb_queue_len(&failq); - - while (num_skbs--) { - skb = __skb_dequeue(&failq); - if (copy) { - cp_skb = skb_copy(skb, GFP_ATOMIC); - if (cp_skb) - __skb_queue_tail(&failq, cp_skb); + skb_queue_walk_safe(&failq, fskb, tmp) { + if (skb_queue_len(&gate_mpath->frame_queue) >= + MESH_FRAME_QUEUE_LEN) { + mpath_dbg(gate_mpath->sdata, "mpath queue full!\n"); + break; } + skb = skb_copy(fskb, GFP_ATOMIC); + if (WARN_ON(!skb)) + break; + prepare_for_gate(skb, gate_mpath->dst, gate_mpath); - __skb_queue_tail(&gateq, skb); + skb_queue_tail(&gate_mpath->frame_queue, skb); + + if (copy) + continue; + + __skb_unlink(fskb, &failq); + kfree_skb(fskb); } - spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags); - skb_queue_splice(&gateq, &gate_mpath->frame_queue); mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); - spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags); if (!copy) return; -- cgit v1.2.1 From e687f61eedab8895e5669cb82cebe0253631cd8c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sun, 12 Aug 2012 18:24:55 +0200 Subject: mac80211: add supported rates change notification in IBSS In IBSS it is possible that the supported rates set for a station changes over time (e.g. it gets first initialised as an empty set because of no available information about rates and updated later). In this case the driver has to be notified about the change in order to update its internal table accordingly (if needed). This behaviour is needed by all those drivers that handle rc internally but leave stations management to mac80211 Reported-by: Gui Iribarren Signed-off-by: Antonio Quartulli [Johannes - add docs, validate IBSS mode only, fix compilation] Signed-off-by: Johannes Berg --- net/mac80211/driver-ops.h | 3 +++ net/mac80211/ibss.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index a81117a83996..a81154d27291 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -528,6 +528,9 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, sdata = get_bss_sdata(sdata); check_sdata_in_driver(sdata); + WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && + sdata->vif.type != NL80211_IFTYPE_ADHOC); + trace_drv_sta_rc_update(local, sdata, sta, changed); if (local->ops->sta_rc_update) local->ops->sta_rc_update(&local->hw, &sdata->vif, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1ebda2f9e57b..a9d93285dba7 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -459,8 +459,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, } } - if (sta && rates_updated) + if (sta && rates_updated) { + drv_sta_rc_update(local, sdata, &sta->sta, + IEEE80211_RC_SUPP_RATES_CHANGED); rate_control_rate_init(sta); + } rcu_read_unlock(); } -- cgit v1.2.1 From 4c29867790131c281ef96af507d85e3e5f829408 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Jul 2012 11:34:31 +0200 Subject: mac80211: support A-MPDU status reporting Support getting A-MPDU status information from the drivers and reporting it to userspace via radiotap in the standard fields. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0cb4edee6af5..78bf6c7e80c8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -60,7 +60,9 @@ static inline int should_drop_frame(struct sk_buff *skb, struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + if (status->flag & (RX_FLAG_FAILED_FCS_CRC | + RX_FLAG_FAILED_PLCP_CRC | + RX_FLAG_AMPDU_IS_ZEROLEN)) return 1; if (unlikely(skb->len < 16 + present_fcs_len)) return 1; @@ -91,6 +93,13 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) /* HT info */ len += 3; + if (status->flag & RX_FLAG_AMPDU_DETAILS) { + /* padding */ + while (len & 3) + len++; + len += 8; + } + return len; } @@ -215,6 +224,37 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; *pos++ = status->rate_idx; } + + if (status->flag & RX_FLAG_AMPDU_DETAILS) { + u16 flags = 0; + + /* ensure 4 byte alignment */ + while ((pos - (u8 *)rthdr) & 3) + pos++; + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); + put_unaligned_le32(status->ampdu_reference, pos); + pos += 4; + if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN) + flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN; + if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN) + flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN; + if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN) + flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN; + if (status->flag & RX_FLAG_AMPDU_IS_LAST) + flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST; + if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR) + flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR; + if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) + flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN; + put_unaligned_le16(flags, pos); + pos += 2; + if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) + *pos++ = status->ampdu_delimiter_crc; + else + *pos++ = 0; + *pos++ = 0; + } } /* -- cgit v1.2.1 From 90bcf867ceef50155a1a14af4dc248061f6b8b94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 15:48:38 +0200 Subject: mac80211: remove unneeded 'bssid' variable There's no need to copy the BSSID just to print it, remove the unnecessary variable. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9d60b4993635..b7c05bb3b672 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1696,7 +1696,6 @@ 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); @@ -1705,9 +1704,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) return; } - memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); - - sdata_info(sdata, "Connection to AP %pM lost\n", bssid); + sdata_info(sdata, "Connection to AP %pM lost\n", + ifmgd->associated->bssid); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, -- cgit v1.2.1 From 57eebdf3c28fe7134597acad529fc40f99b76601 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 15:50:46 +0200 Subject: mac80211: clean up CSA handling code Clean up the CSA handling code by moving some of it out of the if and using a C99 initializer for the struct passed to the driver method. While at it, also add a comment that we should wait for a beacon after switching the channel. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b7c05bb3b672..ae524c9081ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -712,6 +712,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) /* XXX: shouldn't really modify cfg80211-owned data! */ ifmgd->associated->channel = sdata->local->oper_channel; + /* XXX: wait for a beacon first? */ ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); out: @@ -788,36 +789,33 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, sdata->local->csa_channel = new_ch; + ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + + if (sw_elem->mode) + ieee80211_stop_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); + if (sdata->local->ops->channel_switch) { /* use driver's channel switch callback */ - struct ieee80211_channel_switch ch_switch; - memset(&ch_switch, 0, sizeof(ch_switch)); - ch_switch.timestamp = timestamp; - if (sw_elem->mode) { - ch_switch.block_tx = true; - ieee80211_stop_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); - } - ch_switch.channel = new_ch; - ch_switch.count = sw_elem->count; - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + struct ieee80211_channel_switch ch_switch = { + .timestamp = timestamp, + .block_tx = sw_elem->mode, + .channel = new_ch, + .count = sw_elem->count, + }; + drv_channel_switch(sdata->local, &ch_switch); return; } /* channel switch handled in software */ - if (sw_elem->count <= 1) { + if (sw_elem->count <= 1) ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); - } else { - if (sw_elem->mode) - ieee80211_stop_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + else mod_timer(&ifmgd->chswitch_timer, jiffies + msecs_to_jiffies(sw_elem->count * cbss->beacon_interval)); - } } static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.1 From 3049000b97bbfc90aa9ba413eadc4007e5bce2e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 15:53:45 +0200 Subject: mac80211: fix CSA handling timer The time until the channel switch is in TU, not in milliseconds, so use TU_TO_EXP_TIME() to correctly program the timer. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae524c9081ee..9e61fe127a33 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -813,9 +813,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); else mod_timer(&ifmgd->chswitch_timer, - jiffies + - msecs_to_jiffies(sw_elem->count * - cbss->beacon_interval)); + TU_TO_EXP_TIME(sw_elem->count * + cbss->beacon_interval)); } static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.1 From 5bc1420b11903e9f8c470d3b33061b8de0c5c005 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 16:13:02 +0200 Subject: mac80211: check size of channel switch IE when parsing The channel switch IE has a fixed size, so we can discard it in parsing if it's not the right size and use the right struct pointer. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/mlme.c | 10 +++------- net/mac80211/util.c | 7 +++++-- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e22aee83ba53..793f03e15191 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1136,7 +1136,7 @@ struct ieee802_11_elems { u8 *prep; u8 *perr; struct ieee80211_rann_ie *rann; - u8 *ch_switch_elem; + struct ieee80211_channel_sw_ie *ch_switch_ie; u8 *country_elem; u8 *pwr_constr_elem; u8 *quiet_elem; /* first quite element */ @@ -1162,7 +1162,6 @@ struct ieee802_11_elems { u8 preq_len; u8 prep_len; u8 perr_len; - u8 ch_switch_elem_len; u8 country_elem_len; u8 pwr_constr_elem_len; u8 quiet_elem_len; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9e61fe127a33..b9cb8dbe34d9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2267,14 +2267,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->iflist_mtx); } - if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && - (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, - ETH_ALEN) == 0)) { - struct ieee80211_channel_sw_ie *sw_elem = - (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; - ieee80211_sta_process_chanswitch(sdata, sw_elem, + if (elems->ch_switch_ie && + memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) + ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, bss, rx_status->mactime); - } } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 99e4258bdb26..7dff94e43a0c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -768,8 +768,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, elem_parse_failed = true; break; case WLAN_EID_CHANNEL_SWITCH: - elems->ch_switch_elem = pos; - elems->ch_switch_elem_len = elen; + if (elen != sizeof(struct ieee80211_channel_sw_ie)) { + elem_parse_failed = true; + break; + } + elems->ch_switch_ie = (void *)pos; break; case WLAN_EID_QUIET: if (!elems->quiet_elem) { -- cgit v1.2.1 From cc74c0c7d6d623d0d3f13ef64895937edb7b3177 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 16:49:34 +0200 Subject: mac80211: make ieee80211_beacon_connection_loss_work static There's no need to declare the function in the header file since it's only used in a single place, so make it static. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/mlme.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 793f03e15191..2a80698b6324 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1430,7 +1430,6 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr); void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr, bool ack); -void ieee80211_beacon_connection_loss_work(struct work_struct *work); void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, enum queue_stop_reason reason); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b9cb8dbe34d9..ddb2db5c5b05 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1720,7 +1720,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->mtx); } -void ieee80211_beacon_connection_loss_work(struct work_struct *work) +static void ieee80211_beacon_connection_loss_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, -- cgit v1.2.1 From 98104fdeda63d57631c9f89e90a7b83b58fcee40 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 16 Jun 2012 00:19:54 +0200 Subject: cfg80211: add P2P Device abstraction In order to support using a different MAC address for the P2P Device address we must first have a P2P Device abstraction that can be assigned a MAC address. This abstraction will also be useful to support offloading P2P operations to the device, e.g. periodic listen for discoverability. Currently, the driver is responsible for assigning a MAC address to the P2P Device, but this could be changed by allowing a MAC address to be given to the NEW_INTERFACE command. As it has no associated netdev, a P2P Device can only be identified by its wdev identifier but the previous patches allowed using the wdev identifier in various APIs, e.g. remain-on-channel. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 3 +++ net/mac80211/util.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fbab7a84ca21..366d9d3e84c4 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -449,6 +449,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) case NUM_NL80211_IFTYPES: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_P2P_DEVICE: /* cannot happen */ WARN_ON(1); break; @@ -1146,6 +1147,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_AP_VLAN: break; + case NL80211_IFTYPE_P2P_DEVICE: + /* not yet supported */ case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: BUG(); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7dff94e43a0c..9a4e4e30ea6c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1390,6 +1390,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_MONITOR: /* ignore virtual */ break; + case NL80211_IFTYPE_P2P_DEVICE: + /* not yet supported */ case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: case NL80211_IFTYPE_P2P_CLIENT: -- cgit v1.2.1 From f142c6b906da451ded2c7a8e17b2a0e6fee3e891 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jun 2012 20:07:15 +0200 Subject: mac80211: support P2P Device abstraction After cfg80211 got a P2P Device abstraction, add support to mac80211. Whether it really is supported or not will depend on whether or not the driver has support for it, but mac80211 needs to change to be able to support drivers that need a P2P Device. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 18 ++++ net/mac80211/driver-ops.h | 2 +- net/mac80211/ieee80211_i.h | 4 + net/mac80211/iface.c | 231 +++++++++++++++++++++++++++++---------------- net/mac80211/main.c | 9 ++ net/mac80211/offchannel.c | 6 ++ net/mac80211/rx.c | 14 ++- net/mac80211/status.c | 22 +++-- net/mac80211/trace.h | 2 +- net/mac80211/util.c | 14 ++- 10 files changed, 226 insertions(+), 96 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8052a7ad03a6..69b322f6ca2e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -102,6 +102,18 @@ static int ieee80211_change_iface(struct wiphy *wiphy, return 0; } +static int ieee80211_start_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + return ieee80211_do_open(wdev, true); +} + +static void ieee80211_stop_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev)); +} + static int ieee80211_set_noack_map(struct wiphy *wiphy, struct net_device *dev, u16 noack_map) @@ -1774,6 +1786,7 @@ static int ieee80211_scan(struct wiphy *wiphy, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_DEVICE: break; case NL80211_IFTYPE_P2P_GO: if (sdata->local->ops->hw_scan) @@ -2461,6 +2474,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (!sdata->u.mgd.associated) need_offchan = true; break; + case NL80211_IFTYPE_P2P_DEVICE: + need_offchan = true; + break; default: return -EOPNOTSUPP; } @@ -3013,6 +3029,8 @@ struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, .change_virtual_intf = ieee80211_change_iface, + .start_p2p_device = ieee80211_start_p2p_device, + .stop_p2p_device = ieee80211_stop_p2p_device, .add_key = ieee80211_add_key, .del_key = ieee80211_del_key, .get_key = ieee80211_get_key, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index a81154d27291..da9003b20004 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -9,7 +9,7 @@ static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) { WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", - sdata->dev->name, sdata->flags); + sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); } static inline struct ieee80211_sub_if_data * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2a80698b6324..0b81fa807179 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1080,6 +1080,8 @@ struct ieee80211_local { struct idr ack_status_frames; spinlock_t ack_status_lock; + struct ieee80211_sub_if_data __rcu *p2p_sdata; + /* dummy netdev for use w/ NAPI */ struct net_device napi_dev; @@ -1296,6 +1298,8 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, const int offset); +int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); +void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 366d9d3e84c4..152aeea14c85 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -100,6 +100,10 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) sdata->vif.bss_conf.idle = true; continue; } + + if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) + continue; + /* count everything else */ sdata->vif.bss_conf.idle = false; count++; @@ -121,7 +125,8 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) continue; if (sdata->old_idle == sdata->vif.bss_conf.idle) continue; @@ -204,6 +209,8 @@ static inline int identical_mac_addr_allowed(int type1, int type2) { return type1 == NL80211_IFTYPE_MONITOR || type2 == NL80211_IFTYPE_MONITOR || + type1 == NL80211_IFTYPE_P2P_DEVICE || + type2 == NL80211_IFTYPE_P2P_DEVICE || (type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) || (type1 == NL80211_IFTYPE_WDS && (type2 == NL80211_IFTYPE_WDS || @@ -406,9 +413,10 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) * an error on interface type changes that have been pre-checked, so most * checks should be in ieee80211_check_concurrent_iface. */ -static int ieee80211_do_open(struct net_device *dev, bool coming_up) +int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + struct net_device *dev = wdev->netdev; struct ieee80211_local *local = sdata->local; struct sta_info *sta; u32 changed = 0; @@ -443,13 +451,13 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_DEVICE: /* no special treatment */ break; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_P2P_DEVICE: /* cannot happen */ WARN_ON(1); break; @@ -472,7 +480,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) * Copy the hopefully now-present MAC address to * this interface, if it has the special null one. */ - if (is_zero_ether_addr(dev->dev_addr)) { + if (dev && is_zero_ether_addr(dev->dev_addr)) { memcpy(dev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); @@ -537,7 +545,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) local->fif_probe_req++; } - changed |= ieee80211_reset_erp_info(sdata); + if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) + changed |= ieee80211_reset_erp_info(sdata); ieee80211_bss_info_change_notify(sdata, changed); switch (sdata->vif.type) { @@ -548,6 +557,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) netif_carrier_off(dev); break; case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_P2P_DEVICE: break; default: netif_carrier_on(dev); @@ -584,6 +594,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) rate_control_rate_init(sta); netif_carrier_on(dev); + } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { + rcu_assign_pointer(local->p2p_sdata, sdata); } /* @@ -609,7 +621,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) ieee80211_recalc_ps(local, -1); - netif_tx_start_all_queues(dev); + if (dev) + netif_tx_start_all_queues(dev); return 0; err_del_interface: @@ -639,7 +652,7 @@ static int ieee80211_open(struct net_device *dev) if (err) return err; - return ieee80211_do_open(dev, true); + return ieee80211_do_open(&sdata->wdev, true); } static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, @@ -660,7 +673,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, /* * Stop TX on this interface first. */ - netif_tx_stop_all_queues(sdata->dev); + if (sdata->dev) + netif_tx_stop_all_queues(sdata->dev); ieee80211_roc_purge(sdata); @@ -699,14 +713,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, local->fif_probe_req--; } - netif_addr_lock_bh(sdata->dev); - spin_lock_bh(&local->filter_lock); - __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, - sdata->dev->addr_len); - spin_unlock_bh(&local->filter_lock); - netif_addr_unlock_bh(sdata->dev); + if (sdata->dev) { + netif_addr_lock_bh(sdata->dev); + spin_lock_bh(&local->filter_lock); + __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, + sdata->dev->addr_len); + spin_unlock_bh(&local->filter_lock); + netif_addr_unlock_bh(sdata->dev); - ieee80211_configure_filter(local); + ieee80211_configure_filter(local); + } del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -767,6 +783,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ieee80211_adjust_monitor_flags(sdata, -1); ieee80211_configure_filter(local); break; + case NL80211_IFTYPE_P2P_DEVICE: + /* relies on synchronize_rcu() below */ + rcu_assign_pointer(local->p2p_sdata, NULL); + /* fall through */ default: flush_work(&sdata->work); /* @@ -877,9 +897,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) * Called when the netdev is removed or, by the code below, before * the interface type changes. */ -static void ieee80211_teardown_sdata(struct net_device *dev) +static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; int flushed; int i; @@ -900,6 +919,11 @@ static void ieee80211_teardown_sdata(struct net_device *dev) WARN_ON(flushed); } +static void ieee80211_uninit(struct net_device *dev) +{ + ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); +} + static u16 ieee80211_netdev_select_queue(struct net_device *dev, struct sk_buff *skb) { @@ -909,7 +933,7 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev, static const struct net_device_ops ieee80211_dataif_ops = { .ndo_open = ieee80211_open, .ndo_stop = ieee80211_stop, - .ndo_uninit = ieee80211_teardown_sdata, + .ndo_uninit = ieee80211_uninit, .ndo_start_xmit = ieee80211_subif_start_xmit, .ndo_set_rx_mode = ieee80211_set_multicast_list, .ndo_change_mtu = ieee80211_change_mtu, @@ -940,7 +964,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, static const struct net_device_ops ieee80211_monitorif_ops = { .ndo_open = ieee80211_open, .ndo_stop = ieee80211_stop, - .ndo_uninit = ieee80211_teardown_sdata, + .ndo_uninit = ieee80211_uninit, .ndo_start_xmit = ieee80211_monitor_start_xmit, .ndo_set_rx_mode = ieee80211_set_multicast_list, .ndo_change_mtu = ieee80211_change_mtu, @@ -1099,7 +1123,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, /* and set some type-dependent values */ sdata->vif.type = type; sdata->vif.p2p = false; - sdata->dev->netdev_ops = &ieee80211_dataif_ops; sdata->wdev.iftype = type; sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); @@ -1107,8 +1130,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->noack_map = 0; - /* only monitor differs */ - sdata->dev->type = ARPHRD_ETHER; + /* only monitor/p2p-device differ */ + if (sdata->dev) { + sdata->dev->netdev_ops = &ieee80211_dataif_ops; + sdata->dev->type = ARPHRD_ETHER; + } skb_queue_head_init(&sdata->skb_queue); INIT_WORK(&sdata->work, ieee80211_iface_work); @@ -1146,9 +1172,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_AP_VLAN: - break; case NL80211_IFTYPE_P2P_DEVICE: - /* not yet supported */ + break; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: BUG(); @@ -1215,7 +1240,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, ieee80211_do_stop(sdata, false); - ieee80211_teardown_sdata(sdata->dev); + ieee80211_teardown_sdata(sdata); ret = drv_change_interface(local, sdata, internal_type, p2p); if (ret) @@ -1230,7 +1255,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, ieee80211_setup_sdata(sdata, type); - err = ieee80211_do_open(sdata->dev, false); + err = ieee80211_do_open(&sdata->wdev, false); WARN(err, "type change: do_open returned %d", err); return ret; @@ -1257,7 +1282,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, return ret; } else { /* Purge and reset type-dependent state. */ - ieee80211_teardown_sdata(sdata->dev); + ieee80211_teardown_sdata(sdata); ieee80211_setup_sdata(sdata, type); } @@ -1273,8 +1298,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, } static void ieee80211_assign_perm_addr(struct ieee80211_local *local, - struct net_device *dev, - enum nl80211_iftype type) + u8 *perm_addr, enum nl80211_iftype type) { struct ieee80211_sub_if_data *sdata; u64 mask, start, addr, val, inc; @@ -1283,7 +1307,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, int i; /* default ... something at least */ - memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + memcpy(perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && local->hw.wiphy->n_addresses <= 1) @@ -1302,7 +1326,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_AP) continue; - memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); + memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); break; } /* keep default if no AP interface present */ @@ -1321,7 +1345,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } if (!used) { - memcpy(dev->perm_addr, + memcpy(perm_addr, local->hw.wiphy->addresses[i].addr, ETH_ALEN); break; @@ -1372,7 +1396,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } if (!used) { - memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); + memcpy(perm_addr, tmp_addr, ETH_ALEN); break; } addr = (start & ~mask) | (val & mask); @@ -1388,49 +1412,68 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params) { - struct net_device *ndev; + struct net_device *ndev = NULL; struct ieee80211_sub_if_data *sdata = NULL; int ret, i; int txqs = 1; ASSERT_RTNL(); - if (local->hw.queues >= IEEE80211_NUM_ACS) - txqs = IEEE80211_NUM_ACS; - - ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, - name, ieee80211_if_setup, txqs, 1); - if (!ndev) - return -ENOMEM; - dev_net_set(ndev, wiphy_net(local->hw.wiphy)); - - ndev->needed_headroom = local->tx_headroom + - 4*6 /* four MAC addresses */ - + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */ - + 6 /* mesh */ - + 8 /* rfc1042/bridge tunnel */ - - ETH_HLEN /* ethernet hard_header_len */ - + IEEE80211_ENCRYPT_HEADROOM; - ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; - - ret = dev_alloc_name(ndev, ndev->name); - if (ret < 0) - goto fail; - - ieee80211_assign_perm_addr(local, ndev, type); - memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - - /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ - sdata = netdev_priv(ndev); - ndev->ieee80211_ptr = &sdata->wdev; - memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); - memcpy(sdata->name, ndev->name, IFNAMSIZ); + if (type == NL80211_IFTYPE_P2P_DEVICE) { + struct wireless_dev *wdev; + + sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, + GFP_KERNEL); + if (!sdata) + return -ENOMEM; + wdev = &sdata->wdev; + + sdata->dev = NULL; + strlcpy(sdata->name, name, IFNAMSIZ); + ieee80211_assign_perm_addr(local, wdev->address, type); + memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); + } else { + if (local->hw.queues >= IEEE80211_NUM_ACS) + txqs = IEEE80211_NUM_ACS; + + ndev = alloc_netdev_mqs(sizeof(*sdata) + + local->hw.vif_data_size, + name, ieee80211_if_setup, txqs, 1); + if (!ndev) + return -ENOMEM; + dev_net_set(ndev, wiphy_net(local->hw.wiphy)); + + ndev->needed_headroom = local->tx_headroom + + 4*6 /* four MAC addresses */ + + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */ + + 6 /* mesh */ + + 8 /* rfc1042/bridge tunnel */ + - ETH_HLEN /* ethernet hard_header_len */ + + IEEE80211_ENCRYPT_HEADROOM; + ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; + + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) { + free_netdev(ndev); + return ret; + } + + ieee80211_assign_perm_addr(local, ndev->perm_addr, type); + memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + + /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ + sdata = netdev_priv(ndev); + ndev->ieee80211_ptr = &sdata->wdev; + memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); + memcpy(sdata->name, ndev->name, IFNAMSIZ); + + sdata->dev = ndev; + } /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; sdata->local = local; - sdata->dev = ndev; #ifdef CONFIG_INET sdata->arp_filter_state = true; #endif @@ -1459,17 +1502,21 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); - if (params) { - ndev->ieee80211_ptr->use_4addr = params->use_4addr; - if (type == NL80211_IFTYPE_STATION) - sdata->u.mgd.use_4addr = params->use_4addr; - } + if (ndev) { + if (params) { + ndev->ieee80211_ptr->use_4addr = params->use_4addr; + if (type == NL80211_IFTYPE_STATION) + sdata->u.mgd.use_4addr = params->use_4addr; + } - ndev->features |= local->hw.netdev_features; + ndev->features |= local->hw.netdev_features; - ret = register_netdevice(ndev); - if (ret) - goto fail; + ret = register_netdevice(ndev); + if (ret) { + free_netdev(ndev); + return ret; + } + } mutex_lock(&local->iflist_mtx); list_add_tail_rcu(&sdata->list, &local->interfaces); @@ -1479,10 +1526,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, *new_wdev = &sdata->wdev; return 0; - - fail: - free_netdev(ndev); - return ret; } void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) @@ -1494,7 +1537,21 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) mutex_unlock(&sdata->local->iflist_mtx); synchronize_rcu(); - unregister_netdevice(sdata->dev); + + if (sdata->dev) { + unregister_netdevice(sdata->dev); + } else { + cfg80211_unregister_wdev(&sdata->wdev); + kfree(sdata); + } +} + +void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) +{ + if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state))) + return; + ieee80211_do_stop(sdata, true); + ieee80211_teardown_sdata(sdata); } /* @@ -1505,6 +1562,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata, *tmp; LIST_HEAD(unreg_list); + LIST_HEAD(wdev_list); ASSERT_RTNL(); @@ -1512,11 +1570,20 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_del(&sdata->list); - unregister_netdevice_queue(sdata->dev, &unreg_list); + if (sdata->dev) + unregister_netdevice_queue(sdata->dev, &unreg_list); + else + list_add(&sdata->list, &wdev_list); } mutex_unlock(&local->iflist_mtx); unregister_netdevice_many(&unreg_list); list_del(&unreg_list); + + list_for_each_entry_safe(sdata, tmp, &wdev_list, list) { + list_del(&sdata->list); + cfg80211_unregister_wdev(&sdata->wdev); + kfree(sdata); + } } static int netdev_notify(struct notifier_block *nb, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c26e231c733a..e706f9e5b051 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -207,6 +207,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.bssid = NULL; else if (ieee80211_vif_is_mesh(&sdata->vif)) { sdata->vif.bss_conf.bssid = zero; + } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { + sdata->vif.bss_conf.bssid = sdata->vif.addr; + WARN_ONCE(changed & ~(BSS_CHANGED_IDLE), + "P2P Device BSS changed %#x", changed); } else { WARN_ON(1); return; @@ -514,6 +518,11 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_DEAUTH >> 4), }, + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, }; static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 635c3250c668..507121dad082 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -116,6 +116,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; + if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) + continue; + if (sdata->vif.type != NL80211_IFTYPE_MONITOR) set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); @@ -144,6 +147,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) + continue; + if (sdata->vif.type != NL80211_IFTYPE_MONITOR) clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 78bf6c7e80c8..f5258ebc15be 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2812,8 +2812,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, if (!bssid) { if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) return 0; - } else if (!ieee80211_bssid_match(bssid, - sdata->vif.addr)) { + } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { /* * Accept public action frames even when the * BSSID doesn't match, this is used for P2P @@ -2833,9 +2832,18 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) return 0; break; + case NL80211_IFTYPE_P2P_DEVICE: + if (!ieee80211_is_public_action(hdr, skb->len) && + !ieee80211_is_probe_req(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) + return 0; + if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) + status->rx_flags &= ~IEEE80211_RX_RA_MATCH; + break; default: /* should never get here */ - WARN_ON(1); + WARN_ON_ONCE(1); break; } diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 8cd72914cdaf..b0801b7d572d 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -519,19 +519,27 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) u64 cookie = (unsigned long)skb; acked = info->flags & IEEE80211_TX_STAT_ACK; - /* - * TODO: When we have non-netdev frame TX, - * we cannot use skb->dev->ieee80211_ptr - */ - if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) + ieee80211_is_qos_nullfunc(hdr->frame_control)) { cfg80211_probe_status(skb->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); - else + } else if (skb->dev) { cfg80211_mgmt_tx_status( skb->dev->ieee80211_ptr, cookie, skb->data, skb->len, acked, GFP_ATOMIC); + } else { + struct ieee80211_sub_if_data *p2p_sdata; + + rcu_read_lock(); + + p2p_sdata = rcu_dereference(local->p2p_sdata); + if (p2p_sdata) { + cfg80211_mgmt_tx_status( + &p2p_sdata->wdev, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); + } + rcu_read_unlock(); + } } if (unlikely(info->ack_frame_id)) { diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index c6d33b55b2df..65e9a2a1a3e1 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -24,7 +24,7 @@ __string(vif_name, sdata->dev ? sdata->dev->name : "") #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ __entry->p2p = sdata->vif.p2p; \ - __assign_str(vif_name, sdata->dev ? sdata->dev->name : "") + __assign_str(vif_name, sdata->dev ? sdata->dev->name : sdata->name) #define VIF_PR_FMT " vif:%s(%d%s)" #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9a4e4e30ea6c..79bce870ad78 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -276,6 +276,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; + if (!sdata->dev) + continue; + if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) continue; @@ -364,6 +367,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; + if (!sdata->dev) + continue; + for (ac = 0; ac < n_acs; ac++) { if (sdata->vif.hw_queue[ac] == queue || sdata->vif.cab_queue == queue) @@ -902,7 +908,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, drv_conf_tx(local, sdata, ac, &qparam); } - if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { + if (sdata->vif.type != NL80211_IFTYPE_MONITOR && + sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { sdata->vif.bss_conf.qos = enable_qos; if (bss_notify) ieee80211_bss_info_change_notify(sdata, @@ -1391,7 +1398,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* ignore virtual */ break; case NL80211_IFTYPE_P2P_DEVICE: - /* not yet supported */ + changed = BSS_CHANGED_IDLE; + break; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: case NL80211_IFTYPE_P2P_CLIENT: @@ -1578,6 +1586,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; + if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) + continue; if (sdata->vif.type != NL80211_IFTYPE_STATION) goto set; -- cgit v1.2.1 From 6d71117a279aa30574a8af6c7348570c292285c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jun 2012 17:19:44 +0200 Subject: mac80211: add IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF Some devices like the current iwlwifi implementation require that the P2P interface address match the P2P Device address (only one P2P interface is supported.) Add the HW flag IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF that allows drivers to request that P2P Interfaces added while a P2P Device is active get the same MAC address by default. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 152aeea14c85..59f8adc2aa5f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1313,7 +1313,6 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, local->hw.wiphy->n_addresses <= 1) return; - mutex_lock(&local->iflist_mtx); switch (type) { @@ -1331,6 +1330,19 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } /* keep default if no AP interface present */ break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + if (local->hw.flags & IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF) { + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) + continue; + if (!ieee80211_sdata_running(sdata)) + continue; + memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); + goto out_unlock; + } + } + /* otherwise fall through */ default: /* assign a new address if possible -- try n_addresses first */ for (i = 0; i < local->hw.wiphy->n_addresses; i++) { @@ -1405,6 +1417,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, break; } + out_unlock: mutex_unlock(&local->iflist_mtx); } -- cgit v1.2.1 From d348f69f59af769c405c2f43a2d326d7123ef75a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Aug 2012 14:51:44 +0200 Subject: mac80211: simplify buffers in aes_128_cmac_vector There's no need to use a single scratch buffer and calculate offsets into it, just use two separate buffers for the separate variables. Signed-off-by: Johannes Berg --- net/mac80211/aes_cmac.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 8dfd70d8fcfb..a04752e91023 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c @@ -38,14 +38,10 @@ static void gf_mulx(u8 *pad) static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - u8 scratch[2 * AES_BLOCK_SIZE]; - u8 *cbc, *pad; + u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; const u8 *pos, *end; size_t i, e, left, total_len; - cbc = scratch; - pad = scratch + AES_BLOCK_SIZE; - memset(cbc, 0, AES_BLOCK_SIZE); total_len = 0; -- cgit v1.2.1 From 466f310d100ff54f346c1be481af9935c42467b3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Jul 2012 13:51:49 +0200 Subject: mac80211: mesh: don't use global channel type Using local->_oper_channel_type in the mesh code is completely wrong as this value is the combination of the various interface channel types and can be a different value from the mesh interface in case there are multiple virtual interfaces. Use sdata->vif.bss_conf.channel_type instead as it tracks the per-vif channel type. Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 11 ++++++----- net/mac80211/mesh_plink.c | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 035cd0c8ce33..f2d0d213bcfb 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -109,11 +109,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, /* Disallow HT40+/- mismatch */ if (ie->ht_operation && - (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || - local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && + (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || + sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && (sta_channel_type == NL80211_CHAN_HT40MINUS || sta_channel_type == NL80211_CHAN_HT40PLUS) && - local->_oper_channel_type != sta_channel_type) + sdata->vif.bss_conf.channel_type != sta_channel_type) goto mismatch; return true; @@ -375,7 +375,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, sband = local->hw.wiphy->bands[local->oper_channel->band]; if (!sband->ht_cap.ht_supported || - local->_oper_channel_type == NL80211_CHAN_NO_HT) + sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) @@ -392,7 +392,8 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, { struct ieee80211_local *local = sdata->local; struct ieee80211_channel *channel = local->oper_channel; - enum nl80211_channel_type channel_type = local->_oper_channel_type; + enum nl80211_channel_type channel_type = + sdata->vif.bss_conf.channel_type; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[channel->band]; struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 5fd1250f7866..54ce1af491eb 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -117,7 +117,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) u16 ht_opmode; bool non_ht_sta = false, ht20_sta = false; - if (local->_oper_channel_type == NL80211_CHAN_NO_HT) + if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) return 0; rcu_read_lock(); @@ -147,7 +147,8 @@ out: if (non_ht_sta) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; - else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20) + else if (ht20_sta && + sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; else ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; @@ -379,7 +380,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta->sta.supp_rates[band] = rates; if (elems->ht_cap_elem && - sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT) + sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, &sta->sta.ht_cap); -- cgit v1.2.1 From e31583cdf0e2eb71c44b1288a2d93405f972da68 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:07:46 +0200 Subject: mac80211: remove almost unused local variable In ieee80211_beacon_get_tim() we can use the txrc.sband instead of a separate local variable. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2d004ba0615e..2d2f45ecca4d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2300,12 +2300,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; struct beacon_data *beacon; - struct ieee80211_supported_band *sband; enum ieee80211_band band = local->oper_channel->band; struct ieee80211_tx_rate_control txrc; - sband = local->hw.wiphy->bands[band]; - rcu_read_lock(); sdata = vif_to_sdata(vif); @@ -2452,12 +2449,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, memset(&txrc, 0, sizeof(txrc)); txrc.hw = hw; - txrc.sband = sband; + txrc.sband = local->hw.wiphy->bands[band]; txrc.bss_conf = &sdata->vif.bss_conf; txrc.skb = skb; txrc.reported_rate.idx = -1; txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; - if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) + if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1) txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; -- cgit v1.2.1 From 9e99a127b5724d7a2cd9d2973b10981d56e1d647 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:22:06 +0200 Subject: mac80211: remove freq/chantype from debugfs You can now get these values through iw, and they conflict with multi-channel work. Signed-off-by: Johannes Berg --- net/mac80211/debugfs.c | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b8dfb440c8ef..97173f8144d4 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -63,8 +63,6 @@ DEBUGFS_READONLY_FILE(user_power, "%d", local->user_power_level); DEBUGFS_READONLY_FILE(power, "%d", local->hw.conf.power_level); -DEBUGFS_READONLY_FILE(frequency, "%d", - local->hw.conf.channel->center_freq); DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", local->total_ps_buffered); DEBUGFS_READONLY_FILE(wep_iv, "%#08x", @@ -91,33 +89,6 @@ static const struct file_operations reset_ops = { .llseek = noop_llseek, }; -static ssize_t channel_type_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - const char *buf; - - switch (local->hw.conf.channel_type) { - case NL80211_CHAN_NO_HT: - buf = "no ht\n"; - break; - case NL80211_CHAN_HT20: - buf = "ht20\n"; - break; - case NL80211_CHAN_HT40MINUS: - buf = "ht40-\n"; - break; - case NL80211_CHAN_HT40PLUS: - buf = "ht40+\n"; - break; - default: - buf = "???"; - break; - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); -} - static ssize_t hwflags_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -205,7 +176,6 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, } DEBUGFS_READONLY_FILE_OPS(hwflags); -DEBUGFS_READONLY_FILE_OPS(channel_type); DEBUGFS_READONLY_FILE_OPS(queues); /* statistics stuff */ @@ -272,12 +242,10 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.keys = debugfs_create_dir("keys", phyd); - DEBUGFS_ADD(frequency); DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); - DEBUGFS_ADD(channel_type); DEBUGFS_ADD(hwflags); DEBUGFS_ADD(user_power); DEBUGFS_ADD(power); -- cgit v1.2.1 From f9e6e95b63758202fe2ce43bd7c922db2ff50f80 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Jul 2012 14:29:21 +0200 Subject: mac80211: use oper_channel in rate init Using hw.conf.channel is wrong as it could be the temporary channel if the station is added from the workqueue while the device is already on another channel. Use oper_channel instead. Signed-off-by: Johannes Berg --- net/mac80211/rate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 6e4fd32c6617..10de668eb9f6 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -56,7 +56,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) if (!ref) return; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[local->oper_channel->band]; ref->ops->rate_init(ref->priv, sband, ista, priv_sta); set_sta_flag(sta, WLAN_STA_RATE_CONTROL); -- cgit v1.2.1 From 3d01be72e6fe372a0602221090707a1f04c44646 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:27:39 +0200 Subject: mac80211: don't assume channel is set in tracing With the move to multi-channel and away from drv_config(), hw.conf.channel will not always be set, only for devices using the current API instead of the new channel context APIs. Check the channel is set before adding its frequency to the trace data. Also break some overly long lines in the code. Signed-off-by: Johannes Berg --- net/mac80211/trace.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 65e9a2a1a3e1..18d9c8a52e9e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -274,9 +274,12 @@ TRACE_EVENT(drv_config, __entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout; __entry->max_sleep_period = local->hw.conf.max_sleep_period; __entry->listen_interval = local->hw.conf.listen_interval; - __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count; - __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; - __entry->center_freq = local->hw.conf.channel->center_freq; + __entry->long_frame_max_tx_count = + local->hw.conf.long_frame_max_tx_count; + __entry->short_frame_max_tx_count = + local->hw.conf.short_frame_max_tx_count; + __entry->center_freq = local->hw.conf.channel ? + local->hw.conf.channel->center_freq : 0; __entry->channel_type = local->hw.conf.channel_type; __entry->smps = local->hw.conf.smps_mode; ), -- cgit v1.2.1 From 4797c7ba93e4049cdda18045c01bbe563aafff69 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:31:19 +0200 Subject: mac80211: use RX status band instead of current band Even for single-channel devices it is possible that we switch the channel temporarily (e.g. for scanning) but while doing so process a received frame that was still received on the old channel, so checking the current band is racy. Use the band from status instead. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f5258ebc15be..b382605c5733 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2308,7 +2308,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) goto queue; case WLAN_CATEGORY_SPECTRUM_MGMT: - if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) + if (status->band != IEEE80211_BAND_5GHZ) break; if (sdata->vif.type != NL80211_IFTYPE_STATION) -- cgit v1.2.1 From 9b8648704358e42f9865cd6de7cedb5ac0db67e7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:38:32 +0200 Subject: mac80211: check operating channel in scan The optimisation of scanning only on the current channel should check the operating channel. Also modify it to compare channel pointer rather than the frequency. Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bcaee5d12839..4b75ddeef6b1 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -479,11 +479,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); } else if ((req->n_channels == 1) && - (req->channels[0]->center_freq == - local->hw.conf.channel->center_freq)) { - - /* If we are scanning only on the current channel, then - * we do not need to stop normal activities + (req->channels[0] == local->oper_channel)) { + /* + * If we are scanning only on the operating channel + * then we do not need to stop normal activities */ unsigned long next_delay; -- cgit v1.2.1 From c0af07340aae5db9f976bfe71e2e9bcab3169409 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Jul 2012 14:42:10 +0200 Subject: mac80211: convert ops checks to WARN_ON There's no need to BUG_ON when a driver registers invalid operations, warn and return an error. Signed-off-by: Johannes Berg --- net/mac80211/main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e706f9e5b051..bd7529363193 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -545,6 +545,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, int priv_size, i; struct wiphy *wiphy; + if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || + !ops->add_interface || !ops->remove_interface || + !ops->configure_filter)) + return NULL; + if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) return NULL; @@ -597,13 +602,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); - BUG_ON(!ops->tx); - BUG_ON(!ops->start); - BUG_ON(!ops->stop); - BUG_ON(!ops->config); - BUG_ON(!ops->add_interface); - BUG_ON(!ops->remove_interface); - BUG_ON(!ops->configure_filter); local->ops = ops; /* set up some defaults */ -- cgit v1.2.1 From fe94fe05e9fb7c1bea482d1b0fd09029a711cce2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Jul 2012 12:26:34 +0200 Subject: mac80211: pass channel to ieee80211_send_probe_req In multi-channel scenarios, the channel that we will transmit a probe request on isn't always the current channel (which will be NULL anyway) but will instead be the channel that the AP is on. Pass the channel to the ieee80211_send_probe_req() function so it can be used in the different scenarios. The scan code continues to pass the current channel, of course. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/mlme.c | 6 ++++-- net/mac80211/scan.c | 3 ++- net/mac80211/util.c | 6 +++--- 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0b81fa807179..204bfedba306 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1472,7 +1472,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, - u32 ratemask, bool directed, bool no_cck); + u32 ratemask, bool directed, bool no_cck, + struct ieee80211_channel *channel); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ddb2db5c5b05..b65b2149b23b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1577,7 +1577,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ssid_len = ssid[1]; ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, - 0, (u32) -1, true, false); + 0, (u32) -1, true, false, + ifmgd->associated->channel); } ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); @@ -2704,7 +2705,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) * will not answer to direct packet in unassociated state. */ ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], - NULL, 0, (u32) -1, true, false); + NULL, 0, (u32) -1, true, false, + auth_data->bss->channel); } auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4b75ddeef6b1..ef1d69306315 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -416,7 +416,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, local->scan_req->ssids[i].ssid_len, local->scan_req->ie, local->scan_req->ie_len, local->scan_req->rates[band], false, - local->scan_req->no_cck); + local->scan_req->no_cck, + local->hw.conf.channel); /* * After sending probe requests, wait for probe responses diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 79bce870ad78..471fb0516c99 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1163,12 +1163,12 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, - u32 ratemask, bool directed, bool no_cck) + u32 ratemask, bool directed, bool no_cck, + struct ieee80211_channel *channel) { struct sk_buff *skb; - skb = ieee80211_build_probe_req(sdata, dst, ratemask, - sdata->local->hw.conf.channel, + skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, ssid, ssid_len, ie, ie_len, directed); if (skb) { -- cgit v1.2.1 From dcf33963c48e1959c83fda84e336dbb000eefa3f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Jul 2012 15:11:56 +0200 Subject: mac80211: clean up ieee80211_subif_start_xmit There's no need to carry around a return value that is always NETDEV_TX_OK anyway. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2d2f45ecca4d..3b807bcb8fc9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1719,7 +1719,7 @@ netdev_tx_t 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; - int ret = NETDEV_TX_BUSY, head_need; + int head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; struct ieee80211_hdr hdr; @@ -1735,10 +1735,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, u32 info_flags = 0; u16 info_id = 0; - if (unlikely(skb->len < ETH_HLEN)) { - ret = NETDEV_TX_OK; + if (unlikely(skb->len < ETH_HLEN)) goto fail; - } /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ @@ -1786,7 +1784,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; - ret = NETDEV_TX_OK; goto fail; } rcu_read_lock(); @@ -1879,10 +1876,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (tdls_direct) { /* link during setup - throw out frames to peer */ - if (!tdls_auth) { - ret = NETDEV_TX_OK; + if (!tdls_auth) goto fail; - } /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); @@ -1916,7 +1911,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, hdrlen = 24; break; default: - ret = NETDEV_TX_OK; goto fail; } @@ -1961,7 +1955,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); - ret = NETDEV_TX_OK; goto fail; } @@ -2016,10 +2009,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, skb = skb_clone(skb, GFP_ATOMIC); kfree_skb(tmp_skb); - if (!skb) { - ret = NETDEV_TX_OK; + if (!skb) goto fail; - } } hdr.frame_control = fc; @@ -2122,10 +2113,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; fail: - if (ret == NETDEV_TX_OK) - dev_kfree_skb(skb); - - return ret; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } -- cgit v1.2.1 From aba4e6fff8de0c92e53f0e7ef077231e75f7d760 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 22 Aug 2012 14:21:07 +0530 Subject: mac80211: Fix AP mode regression Commit mac80211: avoid using synchronize_rcu in ieee80211_set_probe_resp changed the return value when the probe response template is not present. Revert to the earlier value of 1 - this fixes AP mode for drivers like ath9k. Signed-off-by: Sujith Manoharan Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 69b322f6ca2e..929f897a8ded 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -740,7 +740,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, struct probe_resp *new, *old; if (!resp || !resp_len) - return -EINVAL; + return 1; old = rtnl_dereference(sdata->u.ap.probe_resp); -- cgit v1.2.1 From 0ef24e528f27683620d78c3393b3df73d804828c Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 21 Aug 2012 12:43:35 +0300 Subject: mac80211: Do not check for valid hw_queues for P2P_DEVICE A P2P Device interface does not have a netdev, and is not expected to be used for transmitting data, so there is no need to assign hw queues for it. Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 59f8adc2aa5f..d747da541747 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -278,13 +278,15 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) int n_queues = sdata->local->hw.queues; int i; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == - IEEE80211_INVAL_HW_QUEUE)) - return -EINVAL; - if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= - n_queues)) - return -EINVAL; + if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == + IEEE80211_INVAL_HW_QUEUE)) + return -EINVAL; + if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= + n_queues)) + return -EINVAL; + } } if ((sdata->vif.type != NL80211_IFTYPE_AP) || -- cgit v1.2.1 From 00ea6deb0cb1af8df4ea899330bfd238c93ef164 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Sep 2012 15:54:51 +0200 Subject: mac80211: don't use kerneldoc for ieee80211_add_rx_radiotap_header Doing so creates warnings, but the function is internal and not part of the 802.11 docbooks, so it from kerneldoc. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b382605c5733..61c621e9273f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -103,7 +103,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, return len; } -/** +/* * ieee80211_add_rx_radiotap_header - add radiotap header * * add a radiotap header containing all the fields which the hardware provided. -- cgit v1.2.1 From a4ed53466a289a4139405bf7190c78a8e9d8debf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 6 Sep 2012 13:20:53 +0800 Subject: mac80211: use list_move instead of list_del/list_add Using list_move() instead of list_del() + list_add(). spatch with a semantic match is used to found this problem. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Johannes Berg --- net/mac80211/offchannel.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 507121dad082..83608ac16780 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -233,8 +233,7 @@ static void ieee80211_hw_roc_start(struct work_struct *work) u32 dur = dep->duration; dep->duration = dur - roc->duration; roc->duration = dur; - list_del(&dep->list); - list_add(&dep->list, &roc->list); + list_move(&dep->list, &roc->list); } } out_unlock: -- cgit v1.2.1 From 30dd3edf97abda301150c8cf26fed21e53e3a9ce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Sep 2012 19:15:01 +0200 Subject: mac80211: don't hang on to sched_scan_ies There's no need to keep a copy of the scheduled scan IEs after the driver has been told, if it requires a copy it must make one. Therefore, we can move sched_scan_ies into the function. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/scan.c | 39 ++++++++++++++------------------------- 2 files changed, 14 insertions(+), 26 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 204bfedba306..0a983fbd743d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -970,7 +970,6 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - struct ieee80211_sched_scan_ies sched_scan_ies; struct work_struct sched_scan_stopped_work; struct ieee80211_sub_if_data __rcu *sched_scan_sdata; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 740e414d44f4..e9b19294dd45 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -917,6 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req) { struct ieee80211_local *local = sdata->local; + struct ieee80211_sched_scan_ies sched_scan_ies; int ret, i; mutex_lock(&local->mtx); @@ -935,33 +936,28 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, if (!local->hw.wiphy->bands[i]) continue; - local->sched_scan_ies.ie[i] = kzalloc(2 + - IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + - req->ie_len, - GFP_KERNEL); - if (!local->sched_scan_ies.ie[i]) { + sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + + req->ie_len, + GFP_KERNEL); + if (!sched_scan_ies.ie[i]) { ret = -ENOMEM; goto out_free; } - local->sched_scan_ies.len[i] = - ieee80211_build_preq_ies(local, - local->sched_scan_ies.ie[i], + sched_scan_ies.len[i] = + ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], req->ie, req->ie_len, i, (u32) -1, 0); } - ret = drv_sched_scan_start(local, sdata, req, - &local->sched_scan_ies); - if (ret == 0) { + ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); + if (ret == 0) rcu_assign_pointer(local->sched_scan_sdata, sdata); - goto out; - } out_free: while (i > 0) - kfree(local->sched_scan_ies.ie[--i]); + kfree(sched_scan_ies.ie[--i]); out: mutex_unlock(&local->mtx); return ret; @@ -970,7 +966,7 @@ out: int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - int ret = 0, i; + int ret = 0; mutex_lock(&local->mtx); @@ -979,12 +975,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) goto out; } - if (rcu_access_pointer(local->sched_scan_sdata)) { - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - kfree(local->sched_scan_ies.ie[i]); - + if (rcu_access_pointer(local->sched_scan_sdata)) drv_sched_scan_stop(local, sdata); - } + out: mutex_unlock(&local->mtx); @@ -1006,7 +999,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) struct ieee80211_local *local = container_of(work, struct ieee80211_local, sched_scan_stopped_work); - int i; mutex_lock(&local->mtx); @@ -1015,9 +1007,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) return; } - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - kfree(local->sched_scan_ies.ie[i]); - rcu_assign_pointer(local->sched_scan_sdata, NULL); mutex_unlock(&local->mtx); -- cgit v1.2.1 From 882a7c69d3c605bfacf32e19033447dc70204d45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Aug 2012 22:32:45 +0200 Subject: mac80211: disconnect if channel switch fails Disconnect from the AP if channel switching in the driver failed or if the new channel is unavailable. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 55 +++++++++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0a983fbd743d..e2ab03c773e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -411,6 +411,7 @@ struct ieee80211_if_managed { struct work_struct monitor_work; struct work_struct chswitch_work; struct work_struct beacon_connection_loss_work; + struct work_struct csa_connection_drop_work; unsigned long beacon_timeout; unsigned long probe_timeout; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5d77650d4363..6e374cb04af6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -730,16 +730,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) trace_api_chswitch_done(sdata, success); if (!success) { - /* - * If the channel switch was not successful, stay - * around on the old channel. We currently lack - * good handling of this situation, possibly we - * should just drop the association. - */ - sdata->local->csa_channel = sdata->local->oper_channel; + sdata_info(sdata, + "driver channel switch failed, disconnecting\n"); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + } else { + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } - - ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } EXPORT_SYMBOL(ieee80211_chswitch_done); @@ -784,8 +781,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); - if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) + if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { + sdata_info(sdata, + "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", + ifmgd->associated->bssid, new_freq); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); return; + } sdata->local->csa_channel = new_ch; @@ -1692,7 +1695,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ap_probereq_get); -static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, + bool transmit_frame) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1704,12 +1708,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) return; } - sdata_info(sdata, "Connection to AP %pM lost\n", - ifmgd->associated->bssid); - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - false, frame_buf); + transmit_frame, frame_buf); + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; mutex_unlock(&ifmgd->mtx); /* @@ -1739,10 +1741,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) rcu_read_unlock(); } - if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) - __ieee80211_connection_loss(sdata); - else + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { + sdata_info(sdata, "Connection to AP %pM lost\n", + ifmgd->bssid); + __ieee80211_disconnect(sdata, false); + } else { ieee80211_mgd_probe_ap(sdata, true); + } +} + +static void ieee80211_csa_connection_drop_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.csa_connection_drop_work); + + ieee80211_wake_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); + __ieee80211_disconnect(sdata, true); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -2929,6 +2945,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->monitor_work); cancel_work_sync(&ifmgd->beacon_connection_loss_work); + cancel_work_sync(&ifmgd->csa_connection_drop_work); if (del_timer_sync(&ifmgd->timer)) set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); @@ -2985,6 +3002,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); INIT_WORK(&ifmgd->beacon_connection_loss_work, ieee80211_beacon_connection_loss_work); + INIT_WORK(&ifmgd->csa_connection_drop_work, + ieee80211_csa_connection_drop_work); INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); -- cgit v1.2.1 From 761a48d2603c0ff48024bc70c129b00ec37639ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Sep 2012 13:07:00 +0200 Subject: mac80211: check power constraint IE size when parsing The power constraint IE is always a single byte so check the size when parsing instead of later. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/mlme.c | 10 ++-------- net/mac80211/util.c | 5 ++++- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e2ab03c773e3..b95fa256d438 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1165,7 +1165,6 @@ struct ieee802_11_elems { u8 prep_len; u8 perr_len; u8 country_elem_len; - u8 pwr_constr_elem_len; u8 quiet_elem_len; u8 num_of_quiet_elem; /* can be more the one */ u8 timeout_int_len; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6e374cb04af6..87466942fa82 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -821,18 +821,13 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem, - u8 pwr_constr_elem_len) + u16 capab_info, u8 *pwr_constr_elem) { struct ieee80211_conf *conf = &sdata->local->hw.conf; if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) return; - /* Power constraint IE length should be 1 octet */ - if (pwr_constr_elem_len != 1) - return; - if ((*pwr_constr_elem <= conf->channel->max_reg_power) && (*pwr_constr_elem != sdata->local->power_constr_level)) { sdata->local->power_constr_level = *pwr_constr_elem; @@ -2552,8 +2547,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.pwr_constr_elem) ieee80211_handle_pwr_constr(sdata, le16_to_cpu(mgmt->u.probe_resp.capab_info), - elems.pwr_constr_elem, - elems.pwr_constr_elem_len); + elems.pwr_constr_elem); } ieee80211_bss_info_change_notify(sdata, changed); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 471fb0516c99..ed7543960b16 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, elems->country_elem_len = elen; break; case WLAN_EID_PWR_CONSTRAINT: + if (elen != 1) { + elem_parse_failed = true; + break; + } elems->pwr_constr_elem = pos; - elems->pwr_constr_elem_len = elen; break; case WLAN_EID_TIMEOUT_INTERVAL: elems->timeout_int = pos; -- cgit v1.2.1 From 964b19f9770cd8d299fa99c84b0ff2e90df9c523 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 5 Sep 2012 20:23:56 +0300 Subject: mac80211: use synchronize_net() on key destroying __ieee80211_key_destroy() calls synchronize_rcu() in order to sync the tx path before destroying the key. However, synching the tx path can be done with synchronize_net() as well, which is usually faster (the timing might be important for roaming scenarios). Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 7ae678ba5d67..d27e61aaa71b 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -402,7 +402,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) * Synchronize so the TX path can no longer be using * this key before we free/remove it. */ - synchronize_rcu(); + synchronize_net(); if (key->local) ieee80211_key_disable_hw_accel(key); -- cgit v1.2.1 From 23a85b45cfe954ba418f68352351f21cc28decfd Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 26 Jun 2012 14:37:21 +0200 Subject: mac80211: refactor set_channel_type Split functionality for further reuse. Will prevent code duplication when channel context channel_type merging is introduced. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 67 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 19 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f0f87e5a1d35..0bfc914ddd15 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -68,16 +68,14 @@ ieee80211_get_channel_mode(struct ieee80211_local *local, return mode; } -bool ieee80211_set_channel_type(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - enum nl80211_channel_type chantype) +static enum nl80211_channel_type +ieee80211_get_superchan(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { - struct ieee80211_sub_if_data *tmp; enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; - bool result; + struct ieee80211_sub_if_data *tmp; mutex_lock(&local->iflist_mtx); - list_for_each_entry(tmp, &local->interfaces, list) { if (tmp == sdata) continue; @@ -103,39 +101,70 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, break; } } + mutex_unlock(&local->iflist_mtx); - switch (superchan) { + return superchan; +} + +static bool +ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, + enum nl80211_channel_type chantype2, + enum nl80211_channel_type *compat) +{ + /* + * start out with chantype1 being the result, + * overwriting later if needed + */ + if (compat) + *compat = chantype1; + + switch (chantype1) { case NL80211_CHAN_NO_HT: + if (compat) + *compat = chantype2; + break; case NL80211_CHAN_HT20: /* * allow any change that doesn't go to no-HT * (if it already is no-HT no change is needed) */ - if (chantype == NL80211_CHAN_NO_HT) + if (chantype2 == NL80211_CHAN_NO_HT) break; - superchan = chantype; + if (compat) + *compat = chantype2; break; case NL80211_CHAN_HT40PLUS: case NL80211_CHAN_HT40MINUS: /* allow smaller bandwidth and same */ - if (chantype == NL80211_CHAN_NO_HT) + if (chantype2 == NL80211_CHAN_NO_HT) break; - if (chantype == NL80211_CHAN_HT20) + if (chantype2 == NL80211_CHAN_HT20) break; - if (superchan == chantype) + if (chantype2 == chantype1) break; - result = false; - goto out; + return false; } - local->_oper_channel_type = superchan; + return true; +} + +bool ieee80211_set_channel_type(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum nl80211_channel_type chantype) +{ + enum nl80211_channel_type superchan; + enum nl80211_channel_type compatchan; + + superchan = ieee80211_get_superchan(local, sdata); + if (!ieee80211_channel_types_are_compatible(superchan, chantype, + &compatchan)) + return false; + + local->_oper_channel_type = compatchan; if (sdata) sdata->vif.bss_conf.channel_type = chantype; - result = true; - out: - mutex_unlock(&local->iflist_mtx); + return true; - return result; } -- cgit v1.2.1 From 316b6b5df77db801d62ec381cfae0c38ff84252c Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 18:09:16 +0200 Subject: net/mac80211/scan.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e9b19294dd45..c4cdbde24fd3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -407,7 +407,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, enum ieee80211_band band = local->hw.conf.channel->band; sdata = rcu_dereference_protected(local->scan_sdata, - lockdep_is_held(&local->mtx));; + lockdep_is_held(&local->mtx)); for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( -- cgit v1.2.1 From 6ae16775d6bcd57e64100fda78fd01c8e7e7f08d Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 7 Sep 2012 13:28:52 +0200 Subject: mac80211: move ieee80211_send_deauth_disassoc outside mlme code Move ieee80211_send_deauth_disassoc() to util.c to make it available for the rest of the mac80211 code. Signed-off-by: Antonio Quartulli [reword commit message] Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 5 ++++ net/mac80211/mlme.c | 60 ++++++++-------------------------------------- net/mac80211/util.c | 39 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 50 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b95fa256d438..887452327ba8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -68,6 +68,8 @@ struct ieee80211_local; #define IEEE80211_DEFAULT_MAX_SP_LEN \ IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL +#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) + struct ieee80211_fragment_entry { unsigned long first_frag_time; unsigned int seq; @@ -1458,6 +1460,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, u8 *extra, size_t extra_len, const u8 *bssid, const u8 *da, const u8 *key, u8 key_len, u8 key_idx); +void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, u16 stype, u16 reason, + bool send_frame, u8 *frame_buf); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 87466942fa82..0ca34137a3b5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -88,8 +88,6 @@ 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 @@ -574,46 +572,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ieee80211_tx_skb(sdata, skb); } -static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - 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 = (void *)frame_buf; - - /* 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); - /* u.deauth.reason_code == u.disassoc.reason_code */ - mgmt->u.deauth.reason_code = cpu_to_le16(reason); - - if (send_frame) { - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - DEAUTH_DISASSOC_LEN); - if (!skb) - return; - - 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); - } -} - void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { @@ -1695,7 +1653,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - u8 frame_buf[DEAUTH_DISASSOC_LEN]; + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) { @@ -1713,7 +1671,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, * must be outside lock due to cfg80211, * but that's not a problem. */ - cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); + cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -2645,7 +2603,7 @@ 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]; + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, false, frame_buf); @@ -2655,7 +2613,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, * must be outside lock due to cfg80211, * but that's not a problem. */ - cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); + cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -3538,7 +3496,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u8 frame_buf[DEAUTH_DISASSOC_LEN]; + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; mutex_lock(&ifmgd->mtx); @@ -3566,7 +3524,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); - __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); + __cfg80211_send_deauth(sdata->dev, frame_buf, + IEEE80211_DEAUTH_FRAME_LEN); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); @@ -3580,7 +3539,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 bssid[ETH_ALEN]; - u8 frame_buf[DEAUTH_DISASSOC_LEN]; + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; mutex_lock(&ifmgd->mtx); @@ -3605,7 +3564,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, frame_buf); mutex_unlock(&ifmgd->mtx); - __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); + __cfg80211_send_disassoc(sdata->dev, frame_buf, + IEEE80211_DEAUTH_FRAME_LEN); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ed7543960b16..2017904c69cc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1007,6 +1007,45 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, ieee80211_tx_skb(sdata, skb); } +void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, u16 stype, u16 reason, + bool send_frame, u8 *frame_buf) +{ + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt = (void *)frame_buf; + + /* 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); + /* u.deauth.reason_code == u.disassoc.reason_code */ + mgmt->u.deauth.reason_code = cpu_to_le16(reason); + + if (send_frame) { + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + IEEE80211_DEAUTH_FRAME_LEN); + if (!skb) + return; + + skb_reserve(skb, local->hw.extra_tx_headroom); + + /* copy in frame */ + memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN), + mgmt, IEEE80211_DEAUTH_FRAME_LEN); + + if (sdata->vif.type != NL80211_IFTYPE_STATION || + !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) + IEEE80211_SKB_CB(skb)->flags |= + IEEE80211_TX_INTFL_DONT_ENCRYPT; + + ieee80211_tx_skb(sdata, skb); + } +} + int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, -- cgit v1.2.1 From 2cc59e784b54fb95accbd5f5a9d12041eec72dbc Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 7 Sep 2012 13:28:53 +0200 Subject: mac80211: reply to AUTH with DEAUTH if sta allocation fails in IBSS Whenever a host gets an AUTH frame it first allocates a new station and then replies with another AUTH frame. However, if sta allocations fails the host should send a DEAUTH frame instead to tell the other end that something went wrong. Signed-off-by: Antonio Quartulli [reword commit message a bit] Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a9d93285dba7..7c082517f0c7 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -332,11 +332,27 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, return ieee80211_ibss_finish_sta(sta, auth); } +static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 reason = le16_to_cpu(mgmt->u.deauth.reason_code); + + if (len < IEEE80211_DEAUTH_FRAME_LEN) + return; + + ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM BSSID=%pM (reason: %d)\n", + mgmt->sa, mgmt->da, mgmt->bssid, reason); + sta_info_destroy_addr(sdata, mgmt->sa); +} + static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { u16 auth_alg, auth_transaction; + struct sta_info *sta; + u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; lockdep_assert_held(&sdata->u.ibss.mtx); @@ -352,9 +368,21 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); sta_info_destroy_addr(sdata, mgmt->sa); - ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); + sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); rcu_read_unlock(); + /* + * if we have any problem in allocating the new station, we reply with a + * DEAUTH frame to tell the other end that we had a problem + */ + if (!sta) { + ieee80211_send_deauth_disassoc(sdata, sdata->u.ibss.bssid, + IEEE80211_STYPE_DEAUTH, + WLAN_REASON_UNSPECIFIED, true, + deauth_frame_buf); + return; + } + /* * IEEE 802.11 standard does not require authentication in IBSS * networks and most implementations do not seem to use it. @@ -902,6 +930,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_AUTH: ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); break; + case IEEE80211_STYPE_DEAUTH: + ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); + break; } mgmt_out: -- cgit v1.2.1 From e548c49e6dc6b08b59042930a2e90c69c13c9293 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Sep 2012 17:08:23 +0200 Subject: mac80211: add key flag for management keys Mark keys that might be used to receive management frames so drivers can fall back on software crypto for them if they don't support hardware offload. As the new flag is only set correctly for RX keys and the existing IEEE80211_KEY_FLAG_SW_MGMT flag can only affect TX, also rename the latter to IEEE80211_KEY_FLAG_SW_MGMT_TX. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 32 ++++++++++++++++++++++++++++++++ net/mac80211/tx.c | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03fe6d1cff42..00e31b488adc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -170,6 +170,38 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, } } + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: + if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* Keys without a station are used for TX only */ + if (key->sta && test_sta_flag(key->sta, WLAN_STA_MFP)) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; + case NL80211_IFTYPE_ADHOC: + /* no MFP (yet) */ + break; + case NL80211_IFTYPE_MESH_POINT: +#ifdef CONFIG_MAC80211_MESH + if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; +#endif + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + /* shouldn't happen */ + WARN_ON_ONCE(1); + break; + } + err = ieee80211_key_link(key, sdata, sta); if (err) ieee80211_key_free(sdata->local, key); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 29eb4e678235..e0e0d1d0e830 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -580,7 +580,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; else skip_hw = (tx->key->conf.flags & - IEEE80211_KEY_FLAG_SW_MGMT) && + IEEE80211_KEY_FLAG_SW_MGMT_TX) && ieee80211_is_mgmt(hdr->frame_control); break; case WLAN_CIPHER_SUITE_AES_CMAC: -- cgit v1.2.1 From b22cfcfcae5b2c1e9b43543b6a23e5ef517de8f8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 9 Sep 2012 14:43:51 +0300 Subject: mac80211: use call_rcu() on sta deletion mac80211 calls synchronize_rcu() on sta deletion, which increase the roaming time significantly. Convert it into a call_rcu() mechanism, in order to avoid blocking. Since some of the cleanup functions might sleep, schedule from the call_rcu callback a new work that will do the actual cleanup. In order to make sure the cleanup occurs before the interface went down, flush local->workqueue on ieee80211_do_stop(). Signed-off-by: Yoni Divinsky Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 15 ++++-- net/mac80211/sta_info.c | 121 +++++++++++++++++++++++++++--------------------- net/mac80211/sta_info.h | 2 + 3 files changed, 81 insertions(+), 57 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d747da541747..6f8a73c64fb3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -793,11 +793,20 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, flush_work(&sdata->work); /* * When we get here, the interface is marked down. - * Call synchronize_rcu() to wait for the RX path + * Call rcu_barrier() to wait both for the RX path * should it be using the interface and enqueuing - * frames at this very time on another CPU. + * frames at this very time on another CPU, and + * for the sta free call_rcu callbacks. */ - synchronize_rcu(); + rcu_barrier(); + + /* + * free_sta_rcu() enqueues a work for the actual + * sta cleanup, so we need to flush it while + * sdata is still valid. + */ + flush_workqueue(local->workqueue); + skb_queue_purge(&sdata->skb_queue); /* diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 06fa75ceb025..9c8cd8b8f753 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -91,6 +91,70 @@ static int sta_info_hash_del(struct ieee80211_local *local, return -ENOENT; } +static void free_sta_work(struct work_struct *wk) +{ + struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk); + int ac, i; + struct tid_ampdu_tx *tid_tx; + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + + /* + * At this point, when being called as call_rcu callback, + * neither mac80211 nor the driver can reference this + * sta struct any more except by still existing timers + * associated with this station that we clean up below. + */ + + if (test_sta_flag(sta, WLAN_STA_PS_STA)) { + BUG_ON(!sdata->bss); + + clear_sta_flag(sta, WLAN_STA_PS_STA); + + atomic_dec(&sdata->bss->num_sta_ps); + sta_info_recalc_tim(sta); + } + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); + __skb_queue_purge(&sta->ps_tx_buf[ac]); + __skb_queue_purge(&sta->tx_filtered[ac]); + } + +#ifdef CONFIG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sdata->vif)) { + mesh_accept_plinks_update(sdata); + mesh_plink_deactivate(sta); + del_timer_sync(&sta->plink_timer); + } +#endif + + cancel_work_sync(&sta->drv_unblock_wk); + + /* + * Destroy aggregation state here. It would be nice to wait for the + * driver to finish aggregation stop and then clean up, but for now + * drivers have to handle aggregation stop being requested, followed + * directly by station destruction. + */ + for (i = 0; i < STA_TID_NUM; i++) { + tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); + if (!tid_tx) + continue; + __skb_queue_purge(&tid_tx->pending); + kfree(tid_tx); + } + + sta_info_free(local, sta); +} + +static void free_sta_rcu(struct rcu_head *h) +{ + struct sta_info *sta = container_of(h, struct sta_info, rcu_head); + + ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); +} + /* protected by RCU */ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, const u8 *addr) @@ -241,6 +305,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, spin_lock_init(&sta->lock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock); + INIT_WORK(&sta->free_sta_wk, free_sta_work); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); @@ -654,8 +719,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; - int ret, i, ac; - struct tid_ampdu_tx *tid_tx; + int ret, i; might_sleep(); @@ -711,65 +775,14 @@ int __must_check __sta_info_destroy(struct sta_info *sta) WARN_ON_ONCE(ret != 0); } - /* - * At this point, after we wait for an RCU grace period, - * neither mac80211 nor the driver can reference this - * sta struct any more except by still existing timers - * associated with this station that we clean up below. - */ - synchronize_rcu(); - - if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - BUG_ON(!sdata->bss); - - clear_sta_flag(sta, WLAN_STA_PS_STA); - - atomic_dec(&sdata->bss->num_sta_ps); - sta_info_recalc_tim(sta); - } - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->ps_tx_buf[ac]); - __skb_queue_purge(&sta->tx_filtered[ac]); - } - -#ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_accept_plinks_update(sdata); -#endif - sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); - cancel_work_sync(&sta->drv_unblock_wk); - cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); -#ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { - mesh_plink_deactivate(sta); - del_timer_sync(&sta->plink_timer); - } -#endif - - /* - * Destroy aggregation state here. It would be nice to wait for the - * driver to finish aggregation stop and then clean up, but for now - * drivers have to handle aggregation stop being requested, followed - * directly by station destruction. - */ - for (i = 0; i < STA_TID_NUM; i++) { - tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); - if (!tid_tx) - continue; - __skb_queue_purge(&tid_tx->pending); - kfree(tid_tx); - } - - sta_info_free(local, sta); + call_rcu(&sta->rcu_head, free_sta_rcu); return 0; } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a470e1123a55..c88f161f8118 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -287,6 +287,7 @@ struct sta_ampdu_mlme { struct sta_info { /* General information, mostly static */ struct list_head list; + struct rcu_head rcu_head; struct sta_info __rcu *hnext; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -297,6 +298,7 @@ struct sta_info { spinlock_t lock; struct work_struct drv_unblock_wk; + struct work_struct free_sta_wk; u16 listen_interval; -- cgit v1.2.1 From 1bad53824305807bb5cf49d6b588dd9d867586c6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Sep 2012 11:58:30 +0200 Subject: mac80211: validate skb->dev in the tx status path skb->dev might contain a stale reference to a device that was already deleted, and using it unchecked can lead to invalid pointer accesses. Since this is only used for nl80211 tx, iterate over active interfaces to find a match for skb->dev, and discard the tx status if the device is gone. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/status.c | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b0801b7d572d..2ce89732d0f2 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { u64 cookie = (unsigned long)skb; + bool found = false; + acked = info->flags & IEEE80211_TX_STAT_ACK; - if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { - cfg80211_probe_status(skb->dev, hdr->addr1, - cookie, acked, GFP_ATOMIC); - } else if (skb->dev) { - cfg80211_mgmt_tx_status( - skb->dev->ieee80211_ptr, cookie, skb->data, - skb->len, acked, GFP_ATOMIC); - } else { - struct ieee80211_sub_if_data *p2p_sdata; + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!sdata->dev) + continue; - rcu_read_lock(); + if (skb->dev != sdata->dev) + continue; - p2p_sdata = rcu_dereference(local->p2p_sdata); - if (p2p_sdata) { - cfg80211_mgmt_tx_status( - &p2p_sdata->wdev, cookie, skb->data, - skb->len, acked, GFP_ATOMIC); - } - rcu_read_unlock(); + found = true; + break; + } + + if (!skb->dev) { + sdata = rcu_dereference(local->p2p_sdata); + if (sdata) + found = true; + } + + if (!found) + skb->dev = NULL; + else if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { + cfg80211_probe_status(sdata->dev, hdr->addr1, + cookie, acked, GFP_ATOMIC); + } else { + cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); } + + rcu_read_unlock(); } if (unlikely(info->ack_frame_id)) { -- cgit v1.2.1 From 3a6a0d8ee88d23e7dda28808c2c890c4db50ccb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Sep 2012 17:25:27 +0200 Subject: mac80211: remove unneeded CONFIG_PM ifdef The functions are only called if CONFIG_PM is set as the callers are under an ifdef, so there's no need to also define no-op functions. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 887452327ba8..d11a6f837d69 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1368,7 +1368,6 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 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, struct cfg80211_wowlan *wowlan); @@ -1382,18 +1381,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) return ieee80211_reconfig(hw_to_local(hw)); } -#else -static inline int __ieee80211_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan) -{ - return 0; -} - -static inline int __ieee80211_resume(struct ieee80211_hw *hw) -{ - return 0; -} -#endif /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ -- cgit v1.2.1 From 04b7b2ff50fc77380c1e711f1d7223734547e41b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Sep 2012 13:41:37 +0200 Subject: mac80211: handle power constraint/country IE better Currently, mac80211 uses the power constraint IE, and reduces the regulatory max TX power by it. This can cause issues if the AP is advertising a large power constraint value matching a high TX power in its country IE, for example in this case: ... Country: US Environment: Indoor/Outdoor ... Channels [157 - 157] @ 30 dBm ... Power constraint: 13 dB ... What happened here is that our local regulatory TX power is 15 dBm, and gets reduced by 13 dB so we end up with only 2 dBm effective TX power, which is way too low. Instead, handle the country IE/power constraint IE combined and restrict our TX power to the max of the regulatory power and the maximum power advertised by the AP, in this case 17 dBm (= 30 dBm - 13 dB). Also print a message when this happens to let the user know and help us debug issues with it. Reported-by: Carl A. Cook Tested-by: Carl A. Cook Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/main.c | 8 ++--- net/mac80211/mlme.c | 84 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 22 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d11a6f837d69..8c804550465b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1059,7 +1059,7 @@ struct ieee80211_local { bool disable_dynamic_ps; int user_power_level; /* in dBm */ - int power_constr_level; /* in dBm */ + int ap_power_level; /* in dBm */ enum ieee80211_smps_mode smps_mode; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bd7529363193..416e85eae2d2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -150,13 +150,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) if (test_bit(SCAN_SW_SCANNING, &local->scanning) || test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - test_bit(SCAN_HW_SCANNING, &local->scanning)) + test_bit(SCAN_HW_SCANNING, &local->scanning) || + !local->ap_power_level) power = chan->max_power; else - power = local->power_constr_level ? - min(chan->max_power, - (chan->max_reg_power - local->power_constr_level)) : - chan->max_power; + power = min(chan->max_power, local->ap_power_level); if (local->user_power_level >= 0) power = min(power, local->user_power_level); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0ca34137a3b5..45a9fa63b368 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -779,18 +779,71 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem) + struct ieee80211_channel *channel, + const u8 *country_ie, u8 country_ie_len, + const u8 *pwr_constr_elem) { - struct ieee80211_conf *conf = &sdata->local->hw.conf; + struct ieee80211_country_ie_triplet *triplet; + int chan = ieee80211_frequency_to_channel(channel->center_freq); + int i, chan_pwr, chan_increment, new_ap_level; + bool have_chan_pwr = false; - if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) + /* Invalid IE */ + if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) return; - if ((*pwr_constr_elem <= conf->channel->max_reg_power) && - (*pwr_constr_elem != sdata->local->power_constr_level)) { - sdata->local->power_constr_level = *pwr_constr_elem; - ieee80211_hw_config(sdata->local, 0); + triplet = (void *)(country_ie + 3); + country_ie_len -= 3; + + switch (channel->band) { + default: + WARN_ON_ONCE(1); + /* fall through */ + case IEEE80211_BAND_2GHZ: + case IEEE80211_BAND_60GHZ: + chan_increment = 1; + break; + case IEEE80211_BAND_5GHZ: + chan_increment = 4; + break; } + + /* find channel */ + while (country_ie_len >= 3) { + u8 first_channel = triplet->chans.first_channel; + + if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID) + goto next; + + for (i = 0; i < triplet->chans.num_channels; i++) { + if (first_channel + i * chan_increment == chan) { + have_chan_pwr = true; + chan_pwr = triplet->chans.max_power; + break; + } + } + if (have_chan_pwr) + break; + + next: + triplet++; + country_ie_len -= 3; + } + + if (!have_chan_pwr) + return; + + new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); + + if (sdata->local->ap_power_level == new_ap_level) + return; + + sdata_info(sdata, + "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", + new_ap_level, chan_pwr, *pwr_constr_elem, + sdata->u.mgd.bssid); + sdata->local->ap_power_level = new_ap_level; + ieee80211_hw_config(sdata->local, 0); } void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) @@ -1394,7 +1447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); - local->power_constr_level = 0; + local->ap_power_level = 0; del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -2499,14 +2552,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, bssid, true); } - /* Note: country IE parsing is done for us by cfg80211 */ - if (elems.country_elem) { - /* TODO: IBSS also needs this */ - if (elems.pwr_constr_elem) - ieee80211_handle_pwr_constr(sdata, - le16_to_cpu(mgmt->u.probe_resp.capab_info), - elems.pwr_constr_elem); - } + if (elems.country_elem && elems.pwr_constr_elem && + mgmt->u.probe_resp.capab_info & + cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) + ieee80211_handle_pwr_constr(sdata, local->oper_channel, + elems.country_elem, + elems.country_elem_len, + elems.pwr_constr_elem); ieee80211_bss_info_change_notify(sdata, changed); } -- cgit v1.2.1 From 5d8e4237d2dc73b51ac66dc612c5c42dd7424479 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Sep 2012 10:17:11 +0200 Subject: mac80211: change locking around ieee80211_recalc_smps Make the function acquire the necessary mutex itself to simplify the callers. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 -- net/mac80211/main.c | 2 -- net/mac80211/mlme.c | 2 +- net/mac80211/util.c | 7 ++++--- 4 files changed, 5 insertions(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 00e31b488adc..9bd56a744982 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2070,9 +2070,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, */ if (!sdata->u.mgd.associated || sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { - mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_smps(sdata->local); - mutex_unlock(&sdata->local->iflist_mtx); return 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 416e85eae2d2..c80c4490351c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -364,9 +364,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) struct ieee80211_local *local = container_of(work, struct ieee80211_local, recalc_smps); - mutex_lock(&local->iflist_mtx); ieee80211_recalc_smps(local); - mutex_unlock(&local->iflist_mtx); } #ifdef CONFIG_INET diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 45a9fa63b368..2dbd9e1e3583 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1348,9 +1348,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local, -1); - ieee80211_recalc_smps(local); mutex_unlock(&local->iflist_mtx); + ieee80211_recalc_smps(local); ieee80211_recalc_ps_vif(sdata); netif_tx_start_all_queues(sdata->dev); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2017904c69cc..22ca35054dd0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1606,14 +1606,13 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, return 0; } -/* must hold iflist_mtx */ void ieee80211_recalc_smps(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; int count = 0; - lockdep_assert_held(&local->iflist_mtx); + mutex_lock(&local->iflist_mtx); /* * This function could be improved to handle multiple @@ -1642,12 +1641,14 @@ void ieee80211_recalc_smps(struct ieee80211_local *local) } if (smps_mode == local->smps_mode) - return; + goto unlock; set: local->smps_mode = smps_mode; /* changed flag is auto-detected for this */ ieee80211_hw_config(local, 0); + unlock: + mutex_unlock(&local->iflist_mtx); } static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) -- cgit v1.2.1 From 9385d04f2872057a2029901190391fe192b18693 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 14 Sep 2012 14:18:31 +0800 Subject: mac80211: allow re-open the blocked peer link in mesh Peer link which is blocked using the "iw mesh0 station set plink_action block" is previously not able to re-open using "iw mesh0 station set plink_action open". This patch is intended to solve this. If the station plink state remains at OPN_SNT once open, try block and open again should solve this problem. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9d7ad366ef09..3ab34d816897 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -537,7 +537,8 @@ int mesh_plink_open(struct sta_info *sta) spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; - if (sta->plink_state != NL80211_PLINK_LISTEN) { + if (sta->plink_state != NL80211_PLINK_LISTEN && + sta->plink_state != NL80211_PLINK_BLOCKED) { spin_unlock_bh(&sta->lock); return -EBUSY; } -- cgit v1.2.1 From 2ad4814fb6ddc78ec17079b5dec9e2cd313a944c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Sep 2012 08:20:24 +0200 Subject: mac80211: make reset debugfs depend on CONFIG_PM The suspend/resume code depends on CONFIG_PM, so the reset debugfs file can only be made available if that is enabled. Fengguang Wu's zero-day build testing found this. Signed-off-by: Johannes Berg --- net/mac80211/debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 97173f8144d4..466f4b45dd94 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -70,6 +70,7 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); +#ifdef CONFIG_PM static ssize_t reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -88,6 +89,7 @@ static const struct file_operations reset_ops = { .open = simple_open, .llseek = noop_llseek, }; +#endif static ssize_t hwflags_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -245,7 +247,9 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(queues); +#ifdef CONFIG_PM DEBUGFS_ADD_MODE(reset, 0200); +#endif DEBUGFS_ADD(hwflags); DEBUGFS_ADD(user_power); DEBUGFS_ADD(power); -- cgit v1.2.1 From 552bff0c2fec8953ba3793d75ee335032cc0b47c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Sep 2012 09:26:06 +0200 Subject: cfg80211: constify name parameter to add_virtual_intf The name can't be modified by the driver, make it const. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9bd56a744982..05f3a313db88 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,7 +20,8 @@ #include "rate.h" #include "mesh.h" -static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, + const char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params) -- cgit v1.2.1 From 2514ec86531481713036081e93a353bbd02e542b Mon Sep 17 00:00:00 2001 From: Sylvain Roger Rieunier Date: Thu, 20 Sep 2012 10:03:29 +0200 Subject: mac80211: fix IBSS auth TX debug message In the IBSS auth TX debug message the BSSID and DA address are reversed, fix that. Signed-off-by: Sylvain Roger Rieunier [reword commit message and make it fit 72 cols] Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7c082517f0c7..5f3620f0bc0a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -278,7 +278,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, if (auth && !sdata->u.ibss.auth_frame_registrations) { ibss_dbg(sdata, "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", - sdata->vif.addr, sdata->u.ibss.bssid, addr); + sdata->vif.addr, addr, sdata->u.ibss.bssid); ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, addr, sdata->u.ibss.bssid, NULL, 0, 0); } -- cgit v1.2.1 From 7f1611469b67739df260a6487b2a5e199e8eeba1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2012 12:53:34 +0200 Subject: mac80211: don't send delBA before disassoc When we disassociate, it's not really useful to send delBA action frames since we're going to send disassoc/deauth anyway, so change that. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2dbd9e1e3583..e714ed8bb198 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1399,7 +1399,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, ifmgd->bssid); if (sta) { set_sta_flag(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta, tx); + ieee80211_sta_tear_down_BA_sessions(sta, false); } mutex_unlock(&local->sta_mtx); -- cgit v1.2.1 From 582bb505b67847600ee27e4cda108bb99a8b6306 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2012 12:54:46 +0200 Subject: mac80211: don't send delBA when removing stations When a station is removed and we stop the aggregation sessions, it's not useful to send delBA since this is due to us or the station disassociating or dropping the connection in some other way, so change that. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 9c8cd8b8f753..797dd36a220d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -738,7 +738,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) * will be sufficient. */ set_sta_flag(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta, true); + ieee80211_sta_tear_down_BA_sessions(sta, false); ret = sta_info_hash_del(local, sta); if (ret) -- cgit v1.2.1 From c6f219dc83fbb30c8426fcc7850c28d9d33dee44 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2012 13:04:32 +0200 Subject: mac80211: don't send delBA on addBA failure There's no reason to send a delBA when the peer refused our addBA, so change that. Signed-off-by: Johannes Berg --- net/mac80211/agg-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d0deb3edae21..3195a6307f50 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -869,7 +869,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, } else { ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, - true); + false); } out: -- cgit v1.2.1 From 55fabefe3695241e6ccfa0cd4974f3fa497693dc Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 5 Oct 2012 17:57:39 -0700 Subject: mac80211: call drv_get_tsf() in sleepable context The call to drv_get/set_tsf() was put on the workqueue to perform tsf adjustments since that function might sleep. However it ended up inside a spinlock, whose critical section must be atomic. Do tsf adjustment outside the spinlock instead, and get rid of a warning. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh_sync.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index accfa00ffcdf..a16b7b4b1e02 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -56,7 +56,6 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) u64 tsfdelta; spin_lock_bh(&ifmsh->sync_offset_lock); - if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n", (long long) ifmsh->sync_offset_clockdrift_max); @@ -69,11 +68,11 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) tsfdelta = -beacon_int_fraction; ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; } + spin_unlock_bh(&ifmsh->sync_offset_lock); tsf = drv_get_tsf(local, sdata); if (tsf != -1ULL) drv_set_tsf(local, sdata, tsf + tsfdelta); - spin_unlock_bh(&ifmsh->sync_offset_lock); } static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.1 From c3e7724b6bc2f25e46c38dbe68f09d71fafeafb8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 8 Oct 2012 14:39:33 +0200 Subject: mac80211: use ieee80211_free_txskb to fix possible skb leaks A few places free skbs using dev_kfree_skb even though they're called after ieee80211_subif_start_xmit might have cloned it for tracking tx status. Use ieee80211_free_txskb here to prevent skb leaks. Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- net/mac80211/status.c | 4 ++-- net/mac80211/tx.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2ce89732d0f2..3af0cc4130f1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, skb_queue_len(&local->skb_queue_unreliable); while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && (skb = skb_dequeue(&local->skb_queue_unreliable))) { - dev_kfree_skb_irq(skb); + ieee80211_free_txskb(hw, skb); tmp--; I802_DEBUG_INC(local->tx_status_drop); } @@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", skb_queue_len(&sta->tx_filtered[ac]), !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); } static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e0e0d1d0e830..c9bf83f36657 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) total += skb_queue_len(&sta->ps_tx_buf[ac]); if (skb) { purged++; - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); break; } } @@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ps_dbg(tx->sdata, "STA %pM TX buffer for AC %d full - dropping oldest frame\n", sta->sta.addr, ac); - dev_kfree_skb(old); + ieee80211_free_txskb(&local->hw, old); } else tx->local->total_ps_buffered++; @@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, spin_unlock(&tx->sta->lock); if (purge_skb) - dev_kfree_skb(purge_skb); + ieee80211_free_txskb(&tx->local->hw, purge_skb); } /* reset session timer */ @@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (WARN_ON_ONCE(q >= local->hw.queues)) { __skb_unlink(skb, skbs); - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); continue; } #endif @@ -1356,7 +1356,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(tx->local->tx_handlers_drop); if (tx->skb) - dev_kfree_skb(tx->skb); + ieee80211_free_txskb(&tx->local->hw, tx->skb); else __skb_queue_purge(&tx->skbs); return -1; @@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); if (unlikely(res_prepare == TX_DROP)) { - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); goto out; } else if (unlikely(res_prepare == TX_QUEUED)) { goto out; @@ -1465,7 +1465,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) headroom = max_t(int, 0, headroom); if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { - dev_kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); rcu_read_unlock(); return; } @@ -2050,8 +2050,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, head_need += IEEE80211_ENCRYPT_HEADROOM; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); - if (ieee80211_skb_resize(sdata, skb, head_need, true)) - goto fail; + if (ieee80211_skb_resize(sdata, skb, head_need, true)) { + ieee80211_free_txskb(&local->hw, skb); + return NETDEV_TX_OK; + } } if (encaps_data) { @@ -2184,7 +2186,7 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (WARN_ON(!info->control.vif)) { - kfree_skb(skb); + ieee80211_free_txskb(&local->hw, skb); continue; } -- cgit v1.2.1