Skip to content

Commit

Permalink
mac80211: refactor and move scan RX code
Browse files Browse the repository at this point in the history
This patch refactors some code and moves the scan RX function
to scan.c. More importantly, however, it changes it so that the
MLME's beacon/probe_resp functions aren't invoked when scanning
so that we can remove a "if (scanning)" conditions from two
places.

There's a very slight behavioural change in this patch: now,
when scanning, IBSS and mesh aren't updated even on the same
channel.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Sep 11, 2008
1 parent 0a51b27 commit 98c8fcc
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 136 deletions.
9 changes: 9 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,15 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata,
u8 *ssid, size_t ssid_len);
struct ieee80211_sta_bss *
ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee802_11_elems *elems,
int freq, bool beacon);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss);

#ifdef CONFIG_MAC80211_MESH
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
Expand Down
253 changes: 117 additions & 136 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,9 @@ static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
}

static struct ieee80211_sta_bss *
ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq,
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sta_bss *bss;

bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
Expand Down Expand Up @@ -230,8 +229,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
kfree(bss);
}

static void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss)
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss)
{
local_bh_disable();
if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
Expand Down Expand Up @@ -2443,74 +2442,16 @@ static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local,
return mandatory_rates;
}

static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status,
struct ieee802_11_elems *elems)
struct ieee80211_sta_bss *
ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee802_11_elems *elems,
int freq, bool beacon)
{
struct ieee80211_local *local = sdata->local;
int freq, clen;
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_channel *channel;
u64 beacon_timestamp, rx_timestamp;
u64 supp_rates = 0;
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
enum ieee80211_band band = rx_status->band;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

if (elems->ds_params && elems->ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
else
freq = rx_status->freq;

channel = ieee80211_get_channel(local->hw.wiphy, freq);

if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;

if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
elems->mesh_config && mesh_matches_local(elems, sdata)) {
supp_rates = ieee80211_sta_get_rates(local, elems, band);

mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
mesh_peer_accepts_plinks(elems));
}

if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
supp_rates = ieee80211_sta_get_rates(local, elems, band);

rcu_read_lock();

sta = sta_info_get(local, mgmt->sa);
if (sta) {
u64 prev_rates;

prev_rates = sta->supp_rates[band];
/* make sure mandatory rates are always added */
sta->supp_rates[band] = supp_rates |
ieee80211_sta_get_mandatory_rates(local, band);

#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (sta->supp_rates[band] != prev_rates)
printk(KERN_DEBUG "%s: updated supp_rates set "
"for %s based on beacon info (0x%llx | "
"0x%llx -> 0x%llx)\n",
sdata->dev->name, print_mac(mac, sta->addr),
(unsigned long long) prev_rates,
(unsigned long long) supp_rates,
(unsigned long long) sta->supp_rates[band]);
#endif
} else {
ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
mgmt->sa, supp_rates);
}

rcu_read_unlock();
}
int clen;

#ifdef CONFIG_MAC80211_MESH
if (elems->mesh_config)
Expand All @@ -2528,10 +2469,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
elems->mesh_config_len, freq);
else
#endif
bss = ieee80211_rx_bss_add(sdata, mgmt->bssid, freq,
bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq,
elems->ssid, elems->ssid_len);
if (!bss)
return;
return NULL;
} else {
#if 0
/* TODO: order by RSSI? */
Expand Down Expand Up @@ -2578,17 +2519,114 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
bss->supp_rates_len += clen;
}

bss->band = band;
bss->band = rx_status->band;

beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);

bss->timestamp = beacon_timestamp;
bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
bss->last_update = jiffies;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
bss->qual = rx_status->qual;
bss->wmm_used = elems->wmm_param || elems->wmm_info;

if (!beacon)
bss->last_probe_resp = jiffies;

/*
* For probe responses, or if we don't have any information yet,
* use the IEs from the beacon.
*/
if (!bss->ies || !beacon) {
if (bss->ies == NULL || bss->ies_len < elems->total_len) {
kfree(bss->ies);
bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
}
if (bss->ies) {
memcpy(bss->ies, elems->ie_start, elems->total_len);
bss->ies_len = elems->total_len;
} else
bss->ies_len = 0;
}

return bss;
}

static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status,
struct ieee802_11_elems *elems,
bool beacon)
{
struct ieee80211_local *local = sdata->local;
int freq;
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_channel *channel;
u64 beacon_timestamp, rx_timestamp;
u64 supp_rates = 0;
enum ieee80211_band band = rx_status->band;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

if (elems->ds_params && elems->ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
else
freq = rx_status->freq;

channel = ieee80211_get_channel(local->hw.wiphy, freq);

if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;

if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
elems->mesh_config && mesh_matches_local(elems, sdata)) {
supp_rates = ieee80211_sta_get_rates(local, elems, band);

mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
mesh_peer_accepts_plinks(elems));
}

if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
supp_rates = ieee80211_sta_get_rates(local, elems, band);

rcu_read_lock();

sta = sta_info_get(local, mgmt->sa);
if (sta) {
u64 prev_rates;

prev_rates = sta->supp_rates[band];
/* make sure mandatory rates are always added */
sta->supp_rates[band] = supp_rates |
ieee80211_sta_get_mandatory_rates(local, band);

#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (sta->supp_rates[band] != prev_rates)
printk(KERN_DEBUG "%s: updated supp_rates set "
"for %s based on beacon info (0x%llx | "
"0x%llx -> 0x%llx)\n",
sdata->dev->name, print_mac(mac, sta->addr),
(unsigned long long) prev_rates,
(unsigned long long) supp_rates,
(unsigned long long) sta->supp_rates[band]);
#endif
} else {
ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
mgmt->sa, supp_rates);
}

rcu_read_unlock();
}

bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
freq, beacon);
if (!bss)
return;

/* was just updated in ieee80211_bss_info_update */
beacon_timestamp = bss->timestamp;

/*
* In STA mode, the remaining parameters should not be overridden
* by beacons because they're not necessarily accurate there.
Expand All @@ -2599,21 +2637,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
return;
}

if (bss->ies == NULL || bss->ies_len < elems->total_len) {
kfree(bss->ies);
bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
}
if (bss->ies) {
memcpy(bss->ies, elems->ie_start, elems->total_len);
bss->ies_len = elems->total_len;
} else
bss->ies_len = 0;

bss->wmm_used = elems->wmm_param || elems->wmm_info;

/* check if we need to merge IBSS */
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
!local->sta_sw_scanning && !local->sta_hw_scanning &&
bss->capability & WLAN_CAPABILITY_IBSS &&
bss->freq == local->oper_channel->center_freq &&
elems->ssid_len == sdata->u.sta.ssid_len &&
Expand Down Expand Up @@ -2690,7 +2715,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);

ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);

/* direct probe may be part of the association flow */
if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
Expand Down Expand Up @@ -2721,7 +2746,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,

ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);

ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);

if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
return;
Expand All @@ -2731,15 +2756,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
return;

/* Do not send changes to driver if we are scanning. This removes
* requirement that a driver's bss_info_changed/conf_tx functions
* need to be atomic.
* This is really ugly code, we should rewrite scanning and make
* all this more understandable for humans.
*/
if (local->sta_sw_scanning || local->sta_hw_scanning)
return;

ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
elems.wmm_param_len);

Expand Down Expand Up @@ -2982,41 +2998,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
}


ieee80211_rx_result
ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_mgmt *mgmt;
__le16 fc;

if (skb->len < 2)
return RX_DROP_UNUSABLE;

mgmt = (struct ieee80211_mgmt *) skb->data;
fc = mgmt->frame_control;

if (ieee80211_is_ctl(fc))
return RX_CONTINUE;

if (skb->len < 24)
return RX_DROP_MONITOR;

if (ieee80211_is_probe_resp(fc)) {
ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
}

if (ieee80211_is_beacon(fc)) {
ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
dev_kfree_skb(skb);
return RX_QUEUED;
}

return RX_CONTINUE;
}


static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
Expand Down Expand Up @@ -3233,7 +3214,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
sdata->dev->name, print_mac(mac, bssid));

bss = ieee80211_rx_bss_add(sdata, bssid,
bss = ieee80211_rx_bss_add(local, bssid,
local->hw.conf.channel->center_freq,
sdata->u.sta.ssid, sdata->u.sta.ssid_len);
if (!bss)
Expand Down
Loading

0 comments on commit 98c8fcc

Please sign in to comment.