2008-04-01 17:02:36

by Bill Moss

[permalink] [raw]
Subject: Patch: mac80211: ieee80211_sta.c: ieee80211_rx_bss_info

Based on Jouni Malinen's email comments and some reading of standards, I
have rearranged the code segments in ieee80211_rx_bss_info. I only
changed bss->probe_resp from a counter to a boolean. Patch
ieee80211_sta-4.patch is attached.

HT or high throughput seems to be mostly an N thing. I can't find any
standard covering it. Google uncovered about 6 articles. There were
references to beacons but not to probe responses. I don't think HT is
required at all. It is optional at this point. I moved the HT code block.

This is a temporary fix until someone can do a more detailed study.

This has gone well beyond my original issue. I found that with iwl3945

ip link set wlan0 up
iwconfig wlan0 key xxxxxxxxxxxxxxxxxxxxxxxxxx
iwconfig wlan0 essid mosswap
dhclient wlan0

dhclient -r wlan0
iwconfig wlan0 key off
iwconfig wlan0 ap off
iwconfig wlan0 essid off

ip link set wlan0 up
iwlist wlan0 scan

Produced no scan results because the probe generated by 'iwconfig wlan0
mosswap' put a bss in the bss_list and set bss->probe_resp > 0.
Subsequent beacons were not used for updates and so bss->last_update was
never updated. This caused ieee80211_sta_scan_result to expire this bss.
The simple fix was to move the update code: bss->last_update = jiffies;

Here is the rearranged function. The patch is attached.

static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status,
int beacon)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee802_11_elems elems;
size_t baselen;
int freq, clen;
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
u64 beacon_timestamp, rx_timestamp;
struct ieee80211_channel *channel;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
return; /* ignore ProbeResp to foreign address */

#if 0
printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
dev->name, beacon ? "Beacon" : "Probe Response",
print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
#endif

baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
if (baselen > len)
return;

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

if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
elems.mesh_config && mesh_matches_local(&elems, dev)) {
u64 rates = ieee80211_sta_get_rates(local, &elems,
rx_status->band);

mesh_neighbour_update(mgmt->sa, rates, dev,
mesh_peer_accepts_plinks(&elems, dev));
}

rcu_read_lock();

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

prev_rates = sta->supp_rates[rx_status->band];
sta->supp_rates[rx_status->band] &= supp_rates;
if (sta->supp_rates[rx_status->band] == 0) {
/* No matching rates - this should not really happen.
* Make sure that at least one rate is marked
* supported to avoid issues with TX rate ctrl. */
sta->supp_rates[rx_status->band] =
sdata->u.sta.supp_rates_bits[rx_status->band];
}
if (sta->supp_rates[rx_status->band] != prev_rates) {
printk(KERN_DEBUG "%s: updated supp_rates set for "
"%s based on beacon info (0x%llx & 0x%llx -> "
"0x%llx)\n",
dev->name, print_mac(mac, sta->addr),
(unsigned long long) prev_rates,
(unsigned long long) supp_rates,
(unsigned long long) sta->supp_rates[rx_status->band]);
}
}

rcu_read_unlock();

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;

#ifdef CONFIG_MAC80211_MESH
if (elems.mesh_config)
bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
elems.mesh_id_len, elems.mesh_config, freq);
else
#endif
bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
elems.ssid, elems.ssid_len);
if (!bss) {
#ifdef CONFIG_MAC80211_MESH
if (elems.mesh_config)
bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
elems.mesh_id_len, elems.mesh_config, freq);
else
#endif
bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
elems.ssid, elems.ssid_len);
if (!bss)
return;
} else {
#if 0
/* TODO: order by RSSI? */
spin_lock_bh(&local->sta_bss_lock);
list_move_tail(&bss->list, &local->sta_bss_list);
spin_unlock_bh(&local->sta_bss_lock);
#endif
}

/* save the ERP value so that it is available at association time */
if (elems.erp_info && elems.erp_info_len >= 1) {
bss->erp_value = elems.erp_info[0];
bss->has_erp_value = 1;
}

if (elems.ht_cap_elem &&
(!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
kfree(bss->ht_ie);
bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
if (bss->ht_ie) {
memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
elems.ht_cap_elem_len + 2);
bss->ht_ie_len = elems.ht_cap_elem_len + 2;
} else
bss->ht_ie_len = 0;
} else if (!elems.ht_cap_elem && bss->ht_ie) {
kfree(bss->ht_ie);
bss->ht_ie = NULL;
bss->ht_ie_len = 0;
}

bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);

bss->supp_rates_len = 0;
if (elems.supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
if (clen > elems.supp_rates_len)
clen = elems.supp_rates_len;
memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
clen);
bss->supp_rates_len += clen;
}
if (elems.ext_supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
if (clen > elems.ext_supp_rates_len)
clen = elems.ext_supp_rates_len;
memcpy(&bss->supp_rates[bss->supp_rates_len],
elems.ext_supp_rates, clen);
bss->supp_rates_len += clen;
}

bss->band = rx_status->band;

bss->timestamp = beacon_timestamp;
bss->last_update = jiffies;
bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
if (!beacon && !bss->probe_resp)
bss->probe_resp = 1;

/* Above here put stuff that must be handled for all cases. */

if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
bss->probe_resp && beacon) {
/* STA mode:
* Do not allow beacon to override data from Probe Response. */
ieee80211_rx_bss_put(dev, bss);
return;
}

/* don't override with a beacon */

if (elems.wpa &&
(!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
kfree(bss->wpa_ie);
bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
if (bss->wpa_ie) {
memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
bss->wpa_ie_len = elems.wpa_len + 2;
} else
bss->wpa_ie_len = 0;
} else if (!elems.wpa && bss->wpa_ie) {
kfree(bss->wpa_ie);
bss->wpa_ie = NULL;
bss->wpa_ie_len = 0;
}

/* don't override with a beacon */

if (elems.rsn &&
(!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
kfree(bss->rsn_ie);
bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
if (bss->rsn_ie) {
memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
bss->rsn_ie_len = elems.rsn_len + 2;
} else
bss->rsn_ie_len = 0;
} else if (!elems.rsn && bss->rsn_ie) {
kfree(bss->rsn_ie);
bss->rsn_ie = NULL;
bss->rsn_ie_len = 0;
}

/*
http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC
In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia
Applications with
Quality of Service in Wi-Fi Networks," Wi- Fi Alliance (September 1,
2004) is incorporated
by reference herein. The inclusion of the WMM Parameters in probe
responses and association
responses is mandatory for WMM enabled networks. The inclusion of the
WMM Parameters in beacons,
however, is optional. */

if (elems.wmm_param &&
(!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
kfree(bss->wmm_ie);
bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
if (bss->wmm_ie) {
memcpy(bss->wmm_ie, elems.wmm_param - 2,
elems.wmm_param_len + 2);
bss->wmm_ie_len = elems.wmm_param_len + 2;
} else
bss->wmm_ie_len = 0;
} else if (!elems.wmm_param && bss->wmm_ie) {
kfree(bss->wmm_ie);
bss->wmm_ie = NULL;
bss->wmm_ie_len = 0;
}

/* 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 &&
memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
if (rx_status->flag & RX_FLAG_TSFT) {
/* in order for correct IBSS merging we need mactime
*
* since mactime is defined as the time the first data
* symbol of the frame hits the PHY, and the timestamp
* of the beacon is defined as "the time that the data
* symbol containing the first bit of the timestamp is
* transmitted to the PHY plus the transmitting STA?s
* delays through its local PHY from the MAC-PHY
* interface to its interface with the WM"
* (802.11 11.1.2) - equals the time this bit arrives at
* the receiver - we have to take into account the
* offset between the two.
* e.g: at 1 MBit that means mactime is 192 usec earlier
* (=24 bytes * 8 usecs/byte) than the beacon timestamp.
*/
int rate = local->hw.wiphy->bands[rx_status->band]->
bitrates[rx_status->rate_idx].bitrate;
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
} else if (local && local->ops && local->ops->get_tsf)
/* second best option: get current TSF */
rx_timestamp = local->ops->get_tsf(local_to_hw(local));
else
/* can't merge without knowing the TSF */
rx_timestamp = -1LLU;
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "RX beacon SA=%s BSSID="
"%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
print_mac(mac, mgmt->sa),
print_mac(mac2, mgmt->bssid),
(unsigned long long)rx_timestamp,
(unsigned long long)beacon_timestamp,
(unsigned long long)(rx_timestamp - beacon_timestamp),
jiffies);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (beacon_timestamp > rx_timestamp) {
#ifndef CONFIG_MAC80211_IBSS_DEBUG
if (net_ratelimit())
#endif
printk(KERN_DEBUG "%s: beacon TSF higher than "
"local TSF - IBSS merge with BSSID %s\n",
dev->name, print_mac(mac, mgmt->bssid));
ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
ieee80211_ibss_add_sta(dev, NULL,
mgmt->bssid, mgmt->sa);
}
}

ieee80211_rx_bss_put(dev, bss);
}

--
Bill Moss
Alumni Distinguished Professor
Mathematical Sciences
Clemson University


Attachments:
ieee80211_sta-4.patch (4.45 kB)