From 8a690674e0601efbe9a7b16a5826fc522645cca3 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 17 Apr 2012 10:54:16 -0700 Subject: mac80211: Support on-channel scan option. This based on an idea posted by Stanislaw Gruszka, though I accept full blame for the implementation! This has been tested with ath9k. The idea is to let users scan on the current operating channel without interrupting normal traffic more than absolutely necessary (changing power level might reset some hardware, for instance). Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 ++ net/mac80211/main.c | 4 +- net/mac80211/rx.c | 2 + net/mac80211/scan.c | 95 +++++++++++++++++++++++++++++++++------------- 4 files changed, 77 insertions(+), 27 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index bd7a451b0849..1d074260acd1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -803,6 +803,8 @@ struct tpt_led_trigger { * well be on the operating channel * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to * determine if we are on the operating channel or not + * @SCAN_ONCHANNEL_SCANNING: Do a software scan on only the current operating + * channel. This should not interrupt normal traffic. * @SCAN_COMPLETED: Set for our scan work function when the driver reported * that the scan completed. * @SCAN_ABORTED: Set for our scan work function when the driver reported @@ -811,6 +813,7 @@ struct tpt_led_trigger { enum { SCAN_SW_SCANNING, SCAN_HW_SCANNING, + SCAN_ONCHANNEL_SCANNING, SCAN_COMPLETED, SCAN_ABORTED, }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ac79d5e8e0d0..b70f7f09da61 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -47,7 +47,8 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; - if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning)) + if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning) || + test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) new_flags |= FIF_BCN_PRBRESP_PROMISC; if (local->fif_probe_req || local->probe_req_reg) @@ -148,6 +149,7 @@ 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)) power = chan->max_power; else diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 54a049123a60..dd2fbec23eeb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -425,6 +425,7 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) if (test_bit(SCAN_HW_SCANNING, &local->scanning) || test_bit(SCAN_SW_SCANNING, &local->scanning) || + test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || local->sched_scanning) return ieee80211_scan_rx(rx->sdata, skb); @@ -2915,6 +2916,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, local->dot11ReceivedFragmentCount++; if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || + test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || test_bit(SCAN_SW_SCANNING, &local->scanning))) status->rx_flags |= IEEE80211_RX_IN_SCAN; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 45f5aa229efd..8282284f835c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -401,6 +401,30 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) round_jiffies_relative(0)); } +static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int i; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + enum ieee80211_band band = local->hw.conf.channel->band; + + for (i = 0; i < local->scan_req->n_ssids; i++) + ieee80211_send_probe_req( + sdata, NULL, + local->scan_req->ssids[i].ssid, + 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); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ + *next_delay = IEEE80211_CHANNEL_TIME; + local->next_scan_state = SCAN_DECISION; +} + static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) { @@ -451,10 +475,47 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->scan_req = req; local->scan_sdata = sdata; - if (local->ops->hw_scan) + if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); - else + } 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 + */ + unsigned long next_delay; + + __set_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning); + + ieee80211_recalc_idle(local); + + /* Notify driver scan is starting, keep order of operations + * same as normal software scan, in case that matters. */ + drv_sw_scan_start(local); + + ieee80211_configure_filter(local); /* accept probe-responses */ + + /* We need to ensure power level is at max for scanning. */ + ieee80211_hw_config(local, 0); + + if ((req->channels[0]->flags & + IEEE80211_CHAN_PASSIVE_SCAN) || + !local->scan_req->n_ssids) { + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + } else { + ieee80211_scan_state_send_probe(local, &next_delay); + next_delay = IEEE80211_CHANNEL_TIME; + } + + /* Now, just wait a bit and we are all done! */ + ieee80211_queue_delayed_work(&local->hw, &local->scan_work, + next_delay); + return 0; + } else { + /* Do normal software scan */ __set_bit(SCAN_SW_SCANNING, &local->scanning); + } ieee80211_recalc_idle(local); @@ -611,30 +672,6 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, local->next_scan_state = SCAN_SEND_PROBE; } -static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, - unsigned long *next_delay) -{ - int i; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - enum ieee80211_band band = local->hw.conf.channel->band; - - for (i = 0; i < local->scan_req->n_ssids; i++) - ieee80211_send_probe_req( - sdata, NULL, - local->scan_req->ssids[i].ssid, - 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); - - /* - * After sending probe requests, wait for probe responses - * on the channel. - */ - *next_delay = IEEE80211_CHANNEL_TIME; - local->next_scan_state = SCAN_DECISION; -} - static void ieee80211_scan_state_suspend(struct ieee80211_local *local, unsigned long *next_delay) { @@ -685,6 +722,12 @@ void ieee80211_scan_work(struct work_struct *work) sdata = local->scan_sdata; + /* When scanning on-channel, the first-callback means completed. */ + if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { + aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); + goto out_complete; + } + if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); goto out_complete; -- cgit v1.2.3-55-g7522 From 54ab1ffb6cd94e5c013d61c192e78e30fdf25f8a Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Wed, 18 Apr 2012 19:23:42 -0700 Subject: mac80211: refactor mesh peer initialization This patch unifies the previous two paths toward mesh peer creation a bit. It also fixes a bug where a peer's changing rates or HT mode wouldn't register on leaving and then returning to the mesh with a sta entry still present. Also clean up locking and clear possibly stale ht cap. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 126 ++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 54 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9c836e774fbd..c3a0b0a4f97f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -82,20 +82,14 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) } /* - * NOTE: This is just an alias for sta_info_alloc(), see notes - * on it in the lifecycle management section! + * Allocate mesh sta entry and insert into station table */ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, - u8 *hw_addr, u32 rates, - struct ieee802_11_elems *elems) + u8 *hw_addr) { - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; struct sta_info *sta; - sband = local->hw.wiphy->bands[local->oper_channel->band]; - - if (local->num_sta >= MESH_MAX_PLINKS) + if (sdata->local->num_sta >= MESH_MAX_PLINKS) return NULL; sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); @@ -108,12 +102,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, set_sta_flag(sta, WLAN_STA_WME); - sta->sta.supp_rates[local->hw.conf.channel->band] = rates; - if (elems->ht_cap_elem) - ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - elems->ht_cap_elem, - &sta->sta.ht_cap); - rate_control_rate_init(sta); + if (sta_info_insert(sta)) + return NULL; return sta; } @@ -274,43 +264,76 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, return 0; } -void mesh_neighbour_update(u8 *hw_addr, u32 rates, - struct ieee80211_sub_if_data *sdata, - struct ieee802_11_elems *elems) +/* mesh_peer_init - initialize new mesh peer and return resulting sta_info + * + * @sdata: local meshif + * @addr: peer's address + * @rates: station's supported rates + * @elems: IEs from beacon or mesh peering frame + * + * call under RCU + */ +static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, + u8 *addr, u32 rates, + struct ieee802_11_elems *elems) { struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; struct sta_info *sta; - rcu_read_lock(); + sband = local->hw.wiphy->bands[local->oper_channel->band]; - sta = sta_info_get(sdata, hw_addr); + sta = sta_info_get(sdata, addr); if (!sta) { - rcu_read_unlock(); - /* Userspace handles peer allocation when security is enabled - * */ - if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) - cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, - elems->ie_start, elems->total_len, - GFP_KERNEL); - else - sta = mesh_plink_alloc(sdata, hw_addr, rates, elems); + sta = mesh_plink_alloc(sdata, addr); if (!sta) - return; - if (sta_info_insert_rcu(sta)) { - rcu_read_unlock(); - return; - } + return NULL; } + spin_lock_bh(&sta->lock); sta->last_rx = jiffies; sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + if (elems->ht_cap_elem) + ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, + elems->ht_cap_elem, + &sta->sta.ht_cap); + else + memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); + + rate_control_rate_init(sta); + spin_unlock_bh(&sta->lock); + + return sta; +} + +void mesh_neighbour_update(u8 *hw_addr, u32 rates, + struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *elems) +{ + struct sta_info *sta; + + /* Userspace handles peer allocation when security is enabled */ + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { + cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, + elems->ie_start, + elems->total_len, + GFP_KERNEL); + return; + } + + rcu_read_lock(); + sta = mesh_peer_init(sdata, hw_addr, rates, elems); + if (!sta) + goto out; + if (mesh_peer_accepts_plinks(elems) && - sta->plink_state == NL80211_PLINK_LISTEN && - sdata->u.mesh.accepting_plinks && - sdata->u.mesh.mshcfg.auto_open_plinks && - rssi_threshold_check(sta, sdata)) + sta->plink_state == NL80211_PLINK_LISTEN && + sdata->u.mesh.accepting_plinks && + sdata->u.mesh.mshcfg.auto_open_plinks && + rssi_threshold_check(sta, sdata)) mesh_plink_open(sta); +out: rcu_read_unlock(); } @@ -587,26 +610,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } else if (!sta) { /* ftype == WLAN_SP_MESH_PEERING_OPEN */ - - rcu_read_unlock(); - if (!mesh_plink_free_count(sdata)) { mpl_dbg("Mesh plink error: no more free plinks\n"); - return; - } - sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems); - if (!sta) { - mpl_dbg("Mesh plink error: plink table full\n"); - return; - } - if (sta_info_insert_rcu(sta)) { rcu_read_unlock(); return; } event = OPN_ACPT; - spin_lock_bh(&sta->lock); } else if (matches_local) { - spin_lock_bh(&sta->lock); switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: if (!mesh_plink_free_count(sdata) || @@ -643,12 +653,19 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m break; default: mpl_dbg("Mesh plink: unknown frame subtype\n"); - spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } - } else { - spin_lock_bh(&sta->lock); + } + + if (event == OPN_ACPT) { + /* allocate sta entry if necessary and update info */ + sta = mesh_peer_init(sdata, mgmt->sa, rates, &elems); + if (!sta) { + mpl_dbg("Mesh plink: failed to init peer!\n"); + rcu_read_unlock(); + return; + } } mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", @@ -656,6 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); reason = 0; + spin_lock_bh(&sta->lock); switch (sta->plink_state) { /* spin_unlock as soon as state is updated at each case */ case NL80211_PLINK_LISTEN: -- cgit v1.2.3-55-g7522 From f743ff4907fa5bc2b460f48ace831a560806a9fb Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Wed, 18 Apr 2012 19:23:43 -0700 Subject: mac80211: refactor mesh peer rate handling To avoid passing supp_rates and basic_rates around all the time, just derive these when needed in mesh_matches_local() and mesh_peer_init(). Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 19 +++++++++---------- net/mac80211/mesh.h | 10 +++++----- net/mac80211/mesh_plink.c | 25 +++++++++++-------------- 3 files changed, 25 insertions(+), 29 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 133c118526fb..598a96a3a051 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -64,18 +64,18 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) /** * mesh_matches_local - check if the config of a mesh point matches ours * - * @ie: information elements of a management frame from the mesh peer * @sdata: local mesh subif - * @basic_rates: BSSBasicRateSet of the peer candidate + * @ie: information elements of a management frame from the mesh peer * * This function checks if the mesh configuration of a mesh point matches the * local mesh configuration, i.e. if both nodes belong to the same mesh network. */ -bool mesh_matches_local(struct ieee802_11_elems *ie, - struct ieee80211_sub_if_data *sdata, u32 basic_rates) +bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *ie) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; + u32 basic_rates = 0; /* * As support for each feature is added, check for matching @@ -96,6 +96,9 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) goto mismatch; + ieee80211_sta_get_rates(local, ie, local->oper_channel->band, + &basic_rates); + if (sdata->vif.bss_conf.basic_rates != basic_rates) goto mismatch; @@ -630,7 +633,6 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee802_11_elems elems; struct ieee80211_channel *channel; - u32 supp_rates = 0, basic_rates = 0; size_t baselen; int freq; enum ieee80211_band band = rx_status->band; @@ -661,12 +663,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; - supp_rates = ieee80211_sta_get_rates(local, &elems, - band, &basic_rates); - if (elems.mesh_id && elems.mesh_config && - mesh_matches_local(&elems, sdata, basic_rates)) - mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); + mesh_matches_local(sdata, &elems)) + mesh_neighbour_update(sdata, mgmt->sa, &elems); if (ifmsh->sync_ops) ifmsh->sync_ops->rx_bcn_presp(sdata, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 4ad738988801..345f0e7d518e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -222,8 +222,8 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, char *addr6); int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, struct ieee80211_sub_if_data *sdata); -bool mesh_matches_local(struct ieee802_11_elems *ie, - struct ieee80211_sub_if_data *sdata, u32 basic_rates); +bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *ie); void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata); @@ -276,9 +276,9 @@ int mesh_path_add_gate(struct mesh_path *mpath); int mesh_path_send_to_gates(struct mesh_path *mpath); int mesh_gate_num(struct ieee80211_sub_if_data *sdata); /* Mesh plinks */ -void mesh_neighbour_update(u8 *hw_addr, u32 rates, - struct ieee80211_sub_if_data *sdata, - struct ieee802_11_elems *ie); +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); void mesh_plink_broken(struct sta_info *sta); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c3a0b0a4f97f..c2af7b3d03cd 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -268,20 +268,22 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, * * @sdata: local meshif * @addr: peer's address - * @rates: station's supported rates * @elems: IEs from beacon or mesh peering frame * * call under RCU */ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, - u8 *addr, u32 rates, + u8 *addr, struct ieee802_11_elems *elems) { struct ieee80211_local *local = sdata->local; + enum ieee80211_band band = local->oper_channel->band; struct ieee80211_supported_band *sband; + u32 rates, basic_rates = 0; struct sta_info *sta; - sband = local->hw.wiphy->bands[local->oper_channel->band]; + sband = local->hw.wiphy->bands[band]; + rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); sta = sta_info_get(sdata, addr); if (!sta) { @@ -292,7 +294,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, spin_lock_bh(&sta->lock); sta->last_rx = jiffies; - sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + sta->sta.supp_rates[band] = rates; if (elems->ht_cap_elem) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, @@ -306,8 +308,8 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, return sta; } -void mesh_neighbour_update(u8 *hw_addr, u32 rates, - struct ieee80211_sub_if_data *sdata, +void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, + u8 *hw_addr, struct ieee802_11_elems *elems) { struct sta_info *sta; @@ -322,7 +324,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, } rcu_read_lock(); - sta = mesh_peer_init(sdata, hw_addr, rates, elems); + sta = mesh_peer_init(sdata, hw_addr, elems); if (!sta) goto out; @@ -479,7 +481,6 @@ void mesh_plink_block(struct sta_info *sta) void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { - struct ieee80211_local *local = sdata->local; struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; @@ -488,7 +489,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m bool deactivated, matches_local = true; u8 ie_len; u8 *baseaddr; - u32 rates, basic_rates = 0; __le16 plid, llid, reason; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG static const char *mplstates[] = { @@ -583,11 +583,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; - rates = ieee80211_sta_get_rates(local, &elems, - rx_status->band, &basic_rates); - if (ftype != WLAN_SP_MESH_PEERING_CLOSE && - (!mesh_matches_local(&elems, sdata, basic_rates))) { + !mesh_matches_local(sdata, &elems)) { matches_local = false; switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: @@ -660,7 +657,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m if (event == OPN_ACPT) { /* allocate sta entry if necessary and update info */ - sta = mesh_peer_init(sdata, mgmt->sa, rates, &elems); + sta = mesh_peer_init(sdata, mgmt->sa, &elems); if (!sta) { mpl_dbg("Mesh plink: failed to init peer!\n"); rcu_read_unlock(); -- cgit v1.2.3-55-g7522 From e76781e48f969e044d318485274b9574f1ccc3dd Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Wed, 18 Apr 2012 19:24:13 -0700 Subject: mac80211: don't set mesh peer ht caps if ht disabled Blindly setting ht caps on a mesh peer's station entry would result in MCS rates being used by the rate control algorithm even if no ht had been configured. Fix this by checking the channel type before assigning ht capabilites. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- 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 c2af7b3d03cd..1ff2a5c63e43 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -295,7 +295,8 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, spin_lock_bh(&sta->lock); sta->last_rx = jiffies; sta->sta.supp_rates[band] = rates; - if (elems->ht_cap_elem) + if (elems->ht_cap_elem && + sdata->local->_oper_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.3-55-g7522 From aee286c2cf94929f90d4d1f64ee9b316007ba284 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Wed, 18 Apr 2012 19:24:14 -0700 Subject: mac80211: fix STA channel width field According to IEEE 802.11 8.4.2.59, set the "STA channel width" bit to 0 if transmitting STA is using a 20mhz channel. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 89c1e5b9ba94..577942bfc024 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1684,7 +1684,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; break; } - if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20) ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; /* -- cgit v1.2.3-55-g7522 From 6ac95b57657d1bf5776f29a1697c123f62d5a58a Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Fri, 20 Apr 2012 09:52:56 -0700 Subject: mac80211: fixup for mesh TSF adjustment latency in Toffset setpoint The original patch defined the correction margin but did not apply it. Signed-off-by: Shinichi Hotori Signed-off-by: Yu Niiro Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index ff60d6bcc631..38d30e8ce6dc 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -195,7 +195,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&ifmsh->sync_offset_lock); } else { - sta->t_offset_setpoint = sta->t_offset; + sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN; set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); msync_dbg("STA %pM : offset was invalid, " " sta->t_offset=%lld", -- cgit v1.2.3-55-g7522 From 0d8a0a17288e419c2e5e9ce18c8b66b390eb7e23 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Apr 2012 11:57:00 -0700 Subject: mac80211: declare ieee80211_ave_rssi as EXPORT ieee80211_ave_rssi need to be declare as export for driver to use it. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- include/net/mac80211.h | 8 ++++++++ net/mac80211/util.c | 1 + 2 files changed, 9 insertions(+) (limited to 'net/mac80211') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bebd89f7f6c3..da3658177997 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3802,6 +3802,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb, bool need_basic); +/** + * ieee80211_ave_rssi - report the average rssi for the specified interface + * + * @vif: the specified virtual interface + * + * This function return the average rssi value for the requested interface. + * It assumes that the given vif is valid. + */ int ieee80211_ave_rssi(struct ieee80211_vif *vif); #endif /* MAC80211_H */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 577942bfc024..8ba8b49c9531 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1803,3 +1803,4 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif) return ifmgd->ave_beacon_signal; } +EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); -- cgit v1.2.3-55-g7522 From be6bcabc7919522f28c99642b8e04ef7b8e19283 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 23 Apr 2012 09:30:32 -0700 Subject: mac80211: check for non-managed interface Average beacon signal only keep tracked by managed interface, give warning and return 0 for the others. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- net/mac80211/util.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8ba8b49c9531..d9a747d387f0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1801,6 +1801,10 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif) struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) { + /* non-managed type inferfaces */ + return 0; + } return ifmgd->ave_beacon_signal; } EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); -- cgit v1.2.3-55-g7522 From 030ef8f8a59c77d44cadeded6d3a5a12557774f4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Apr 2012 19:49:02 +0200 Subject: mac80211: rename AP variable num_sta_authorized to num_mcast_sta It is only used to test for BSS multicast receivers. Signed-off-by: Felix Fietkau Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 4 ++-- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/sta_info.c | 4 ++-- net/mac80211/tx.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e7af5227e322..ea0122dbd2b3 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -394,7 +394,7 @@ static ssize_t ieee80211_if_parse_uapsd_max_sp_len( __IEEE80211_IF_FILE_W(uapsd_max_sp_len); /* AP attributes */ -IEEE80211_IF_FILE(num_sta_authorized, u.ap.num_sta_authorized, ATOMIC); +IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); @@ -540,7 +540,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) static void add_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(num_sta_authorized); + DEBUGFS_ADD(num_mcast_sta); DEBUGFS_ADD(num_sta_ps); DEBUGFS_ADD(dtim_count); DEBUGFS_ADD(num_buffered_multicast); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1d074260acd1..851fb7dc893c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -282,7 +282,7 @@ struct ieee80211_if_ap { u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; struct sk_buff_head ps_bc_buf; atomic_t num_sta_ps; /* number of stations in PS mode */ - atomic_t num_sta_authorized; /* number of authorized stations */ + atomic_t num_mcast_sta; /* number of stations receiving multicast */ int dtim_count; bool dtim_bc_mc; }; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7fd7ac48f893..4c04eb5e4cae 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1418,14 +1418,14 @@ int sta_info_move_state(struct sta_info *sta, set_bit(WLAN_STA_ASSOC, &sta->_flags); } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { if (sta->sdata->vif.type == NL80211_IFTYPE_AP) - atomic_dec(&sta->sdata->u.ap.num_sta_authorized); + atomic_dec(&sta->sdata->u.ap.num_mcast_sta); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); } break; case IEEE80211_STA_AUTHORIZED: if (sta->sta_state == IEEE80211_STA_ASSOC) { if (sta->sdata->vif.type == NL80211_IFTYPE_AP) - atomic_inc(&sta->sdata->u.ap.num_sta_authorized); + atomic_inc(&sta->sdata->u.ap.num_mcast_sta); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); } break; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0abbef952c14..44001c7e0e58 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -306,7 +306,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) } } else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_data(hdr->frame_control) && - !atomic_read(&tx->sdata->u.ap.num_sta_authorized))) { + !atomic_read(&tx->sdata->u.ap.num_mcast_sta))) { /* * No associated STAs - no need to send multicast * frames. -- cgit v1.2.3-55-g7522 From 7e3ed02c6e65a0cb4c9259c0d34740305d9aa5e7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Apr 2012 19:49:03 +0200 Subject: mac80211: fix num_mcast_sta counting issues Moving a STA to an AP VLAN prevents num_mcast_sta from being decremented once the STA leaves, because sta->sdata changes. Fix this by checking for AP VLANs as well. Also exclude 4-addr VLAN stations from num_mcast_sta - remote 4-addr stations ignore 3-address multicast frames anyway. In a typical bridge configuration they receive the same packets as 4-address unicast. This patch also fixes clearing the sdata->u.vlan.sta pointer when the STA is removed from a 4-addr VLAN. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 19 +++++++++++++++++++ net/mac80211/sta_info.c | 12 ++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 510a745c3108..70b2af2315a6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1005,6 +1005,9 @@ static int ieee80211_change_station(struct wiphy *wiphy, } if (params->vlan && params->vlan != sta->sdata->dev) { + bool prev_4addr = false; + bool new_4addr = false; + vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && @@ -1020,9 +1023,25 @@ static int ieee80211_change_station(struct wiphy *wiphy, } rcu_assign_pointer(vlansdata->u.vlan.sta, sta); + new_4addr = true; + } + + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + sta->sdata->u.vlan.sta) { + rcu_assign_pointer(sta->sdata->u.vlan.sta, NULL); + prev_4addr = true; } sta->sdata = vlansdata; + + if (sta->sta_state == IEEE80211_STA_AUTHORIZED && + prev_4addr != new_4addr) { + if (new_4addr) + atomic_dec(&sta->sdata->bss->num_mcast_sta); + else + atomic_inc(&sta->sdata->bss->num_mcast_sta); + } + ieee80211_send_layer2_update(sta); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4c04eb5e4cae..97a9d6639fb9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1417,15 +1417,19 @@ int sta_info_move_state(struct sta_info *sta, if (sta->sta_state == IEEE80211_STA_AUTH) { set_bit(WLAN_STA_ASSOC, &sta->_flags); } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { - if (sta->sdata->vif.type == NL80211_IFTYPE_AP) - atomic_dec(&sta->sdata->u.ap.num_mcast_sta); + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || + (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + !sta->sdata->u.vlan.sta)) + atomic_dec(&sta->sdata->bss->num_mcast_sta); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); } break; case IEEE80211_STA_AUTHORIZED: if (sta->sta_state == IEEE80211_STA_ASSOC) { - if (sta->sdata->vif.type == NL80211_IFTYPE_AP) - atomic_inc(&sta->sdata->u.ap.num_mcast_sta); + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || + (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + !sta->sdata->u.vlan.sta)) + atomic_inc(&sta->sdata->bss->num_mcast_sta); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); } break; -- cgit v1.2.3-55-g7522 From 94c514fe240fc0dd02187b78facefde8b6744634 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 24 Apr 2012 14:18:28 +0300 Subject: mac80211: Adds clean sdata helper Adds hepler to clean sdata ieee80211_clean_sdata similar way as ieee80211_setup_sdata is implemented. The function will be used by other interfaces later. Signed-off-by: Andrei Emeltchenko Signed-off-by: John W. Linville --- net/mac80211/iface.c | 19 +++++++++++++++---- net/mac80211/mesh.h | 4 +++- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 23d1da376eb3..ba86978dd561 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1031,6 +1031,18 @@ 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) { @@ -1364,8 +1376,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) list_del_rcu(&sdata->list); mutex_unlock(&sdata->local->iflist_mtx); - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_path_flush_by_iface(sdata); + /* clean up type-dependent data */ + ieee80211_clean_sdata(sdata); synchronize_rcu(); unregister_netdevice(sdata->dev); @@ -1386,8 +1398,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_del(&sdata->list); - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_path_flush_by_iface(sdata); + ieee80211_clean_sdata(sdata); unregister_netdevice_queue(sdata->dev, &unreg_list); } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 345f0e7d518e..e3642756f8f4 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -304,7 +304,6 @@ void mesh_pathtbl_unregister(void); int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); -void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); void mesh_path_discard_frame(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata); void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); @@ -345,6 +344,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); void mesh_plink_quiesce(struct sta_info *sta); void mesh_plink_restart(struct sta_info *sta); +void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); #else #define mesh_allocated 0 @@ -358,6 +358,8 @@ static inline void mesh_plink_quiesce(struct sta_info *sta) {} static inline void mesh_plink_restart(struct sta_info *sta) {} static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) { return false; } +static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) +{} #endif #endif /* IEEE80211S_H */ -- cgit v1.2.3-55-g7522