Search Linux Wireless

Patch: mac80211: ieee80211_sta.c: ieee80211_rx_bss_info

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

--- ieee80211_sta.c_orig	2008-03-28 09:38:50.000000000 -0400
+++ ieee80211_sta.c	2008-03-31 23:45:00.000000000 -0400
@@ -2546,22 +2546,29 @@
 #endif
 	}
 
-	bss->band = rx_status->band;
-
-	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;
-	}
-
 	/* 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);
 
@@ -2569,7 +2576,7 @@
 	if (elems.supp_rates) {
 		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
 		if (clen > elems.supp_rates_len)
-			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;
@@ -2577,12 +2584,34 @@
 	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;
+		       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))) {
@@ -2599,6 +2628,8 @@
 		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))) {
@@ -2615,6 +2646,13 @@
 		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))) {
@@ -2631,30 +2669,6 @@
 		bss->wmm_ie = NULL;
 		bss->wmm_ie_len = 0;
 	}
-	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->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++;
 
 	/* check if we need to merge IBSS */
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux