2008-02-05 10:49:23

by Bruno Randolf

[permalink] [raw]
Subject: [PATCH 0/2] ibss merge resend

hello!

i resend my ibss merge patch, in order to address all issues that have come up
since the first try. the first patch just moves the function
ieee80211_sta_join_ibss(), the second one changes functionality.

greetings,

bruno

---

Bruno Randolf (2):
mac80211: enable IBSS merging
mac80211: move function ieee80211_sta_join_ibss()


net/mac80211/ieee80211_sta.c | 385 ++++++++++++++++++++++--------------------
net/mac80211/rx.c | 5 -
2 files changed, 204 insertions(+), 186 deletions(-)



2008-02-05 10:50:04

by Bruno Randolf

[permalink] [raw]
Subject: [PATCH 2/2] mac80211: enable IBSS merging

enable IBSS cell merging. if an IBSS beacon with the same ESSID and a TSF
higher than the local TSF (mactime) is received, we have to join its BSSID.

* move the relevant code section (previously only containing debug code) down
to the end of the function, so we can reuse the bss structure.

* we have to compare the mactime (TSF at the time of packet receive) rather
than the current TSF.

* in IBSS mode we want to allow beacons to override probe response info so we
can correctly do merges.

* we don't only configure beacons based on scan results, so change that
message.

* to enable all this we have to let all beacons thru in IBSS mode, even if they
have a different BSSID.

Signed-off-by: Bruno Randolf <[email protected]>
---

net/mac80211/ieee80211_sta.c | 68 +++++++++++++++++++++++++-----------------
net/mac80211/rx.c | 5 ++-
2 files changed, 45 insertions(+), 28 deletions(-)


diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 08f89fa..7f72f32 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2202,7 +2202,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- u64 timestamp;
+ u64 timestamp, mactime;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

@@ -2220,30 +2220,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
return;

timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
- memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- static unsigned long last_tsf_debug = 0;
- u64 tsf;
- if (local->ops->get_tsf)
- tsf = local->ops->get_tsf(local_to_hw(local));
- else
- tsf = -1LLU;
- if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
- 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)tsf,
- (unsigned long long)timestamp,
- (unsigned long long)(tsf - timestamp),
- jiffies);
- last_tsf_debug = jiffies;
- }
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- }
-
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);

if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
@@ -2329,8 +2305,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,

bss->band = rx_status->band;

- if (bss->probe_resp && beacon) {
- /* Do not allow beacon to override data from Probe Response. */
+ 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;
}
@@ -2434,6 +2412,42 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
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 &&
+ !local->sta_sw_scanning && !local->sta_hw_scanning &&
+ mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
+ 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 */
+ mactime = rx_status->mactime;
+ else if (local && local->ops && local->ops->get_tsf)
+ /* second best option: get current TSF */
+ mactime = local->ops->get_tsf(local_to_hw(local));
+ else
+ /* can't merge without knowing the TSF */
+ mactime = -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)mactime,
+ (unsigned long long)timestamp,
+ (unsigned long long)(mactime - timestamp),
+ jiffies);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ if (mactime <= timestamp) {
+ if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit())
+ 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);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index beda1bf..ed7cf37 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1612,7 +1612,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
case IEEE80211_IF_TYPE_IBSS:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+ return 1;
+ else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
return 0;
rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;


2008-02-06 02:46:54

by Bruno Randolf

[permalink] [raw]
Subject: [PATCH] addressing johannes latest comments and adding a channel check...

mac80211: enable IBSS merging

enable IBSS cell merging. if an IBSS beacon with the same channel, same ESSID
and a TSF higher than the local TSF (mactime) is received, we have to join its
BSSID. while this might not be immediately apparent from reading the 802.11
standard it is compliant and necessary to make IBSS mode functional in many
cases. most drivers have a similar behaviour.

* move the relevant code section (previously only containing debug code) down
to the end of the function, so we can reuse the bss structure.

* we have to compare the mactime (TSF at the time of packet receive) rather
than the current TSF. since some drivers are not able to give a reliable
mactime we fall back to use the current TSF, which will be enough to catch most
(but not all) cases where an IBSS merge is necessary.

* in IBSS mode we want to allow beacons to override probe response info so we
can correctly do merges.

* we don't only configure beacons based on scan results, so change that
message.

* to enable this we have to let all beacons thru in IBSS mode, even if they
have a different BSSID.

Signed-off-by: Bruno Randolf <[email protected]>
---

include/net/mac80211.h | 3 +-
net/mac80211/ieee80211_sta.c | 70 ++++++++++++++++++++++++++----------------
net/mac80211/rx.c | 5 ++-
3 files changed, 49 insertions(+), 29 deletions(-)


diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 460da54..4ae3a12 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -276,7 +276,8 @@ struct ieee80211_tx_control {
* @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
* the frame.
* @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
- * is valid.
+ * is valid. This is useful in monitor mode and necessary for beacon frames
+ * to enable IBSS merging.
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 08f89fa..4df18ae 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2202,7 +2202,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- u64 timestamp;
+ u64 timestamp, mactime;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

@@ -2220,30 +2220,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
return;

timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
- memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- static unsigned long last_tsf_debug = 0;
- u64 tsf;
- if (local->ops->get_tsf)
- tsf = local->ops->get_tsf(local_to_hw(local));
- else
- tsf = -1LLU;
- if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
- 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)tsf,
- (unsigned long long)timestamp,
- (unsigned long long)(tsf - timestamp),
- jiffies);
- last_tsf_debug = jiffies;
- }
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- }
-
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);

if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
@@ -2329,8 +2305,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,

bss->band = rx_status->band;

- if (bss->probe_resp && beacon) {
- /* Do not allow beacon to override data from Probe Response. */
+ 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;
}
@@ -2434,6 +2412,44 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
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 &&
+ !local->sta_sw_scanning && !local->sta_hw_scanning &&
+ mgmt->u.beacon.capab_info & 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 */
+ mactime = rx_status->mactime;
+ else if (local && local->ops && local->ops->get_tsf)
+ /* second best option: get current TSF */
+ mactime = local->ops->get_tsf(local_to_hw(local));
+ else
+ /* can't merge without knowing the TSF */
+ mactime = -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)mactime,
+ (unsigned long long)timestamp,
+ (unsigned long long)(mactime - timestamp),
+ jiffies);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ if (mactime <= timestamp) {
+ if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit())
+ 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);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index beda1bf..ed7cf37 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1612,7 +1612,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
case IEEE80211_IF_TYPE_IBSS:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+ return 1;
+ else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
return 0;
rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;


2008-02-05 11:08:26

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/2] mac80211: enable IBSS merging


> + /* check if we need to merge IBSS */
> + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
> + !local->sta_sw_scanning && !local->sta_hw_scanning &&
> + mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
> + memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {

This needs to test whether elems.ssid_len == sdata->u.sta.ssid_len
(before doing the memcmp to not overrun the frame).

> + if (rx_status->flag & RX_FLAG_TSFT)
> + /* in order for correct IBSS merging we need mactime */
> + mactime = rx_status->mactime;

This needs to be documented (with the RX flag I guess) and b43(legacy)
should be changed to include the TSFT in beacon frames in IBSS mode...

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part

2008-02-05 10:49:43

by Bruno Randolf

[permalink] [raw]
Subject: [PATCH 1/2] mac80211: move function ieee80211_sta_join_ibss()

this moves ieee80211_sta_join_ibss() up for the next patch (ibss merge).

Signed-off-by: Bruno Randolf <[email protected]>
---

net/mac80211/ieee80211_sta.c | 317 +++++++++++++++++++++---------------------
1 files changed, 159 insertions(+), 158 deletions(-)


diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 7be1e73..08f89fa 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2030,6 +2030,165 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev)
}


+static int ieee80211_sta_join_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int res, rates, i, j;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_tx_control control;
+ struct rate_selection ratesel;
+ u8 *pos;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush(local, NULL);
+
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+ memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+ res = ieee80211_if_config(dev);
+ if (res)
+ return res;
+
+ local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ sdata->drop_unencrypted = bss->capability &
+ WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+ res = ieee80211_set_freq(local, bss->freq);
+
+ if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+ "%d MHz\n", dev->name, local->oper_channel->center_freq);
+ return -1;
+ }
+
+ /* Set beacon template */
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ do {
+ if (!skb)
+ break;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+
+ pos = skb_put(skb, 2 + ifsta->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifsta->ssid_len;
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+ rates = bss->supp_rates_len;
+ if (rates > 8)
+ rates = 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, bss->supp_rates, rates);
+
+ if (bss->band == IEEE80211_BAND_2GHZ) {
+ pos = skb_put(skb, 2 + 1);
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = ieee80211_frequency_to_channel(bss->freq);
+ }
+
+ pos = skb_put(skb, 2 + 2);
+ *pos++ = WLAN_EID_IBSS_PARAMS;
+ *pos++ = 2;
+ /* FIX: set ATIM window based on scan results */
+ *pos++ = 0;
+ *pos++ = 0;
+
+ if (bss->supp_rates_len > 8) {
+ rates = bss->supp_rates_len - 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, &bss->supp_rates[8], rates);
+ }
+
+ memset(&control, 0, sizeof(control));
+ rate_control_get_rate(dev, sband, skb, &ratesel);
+ if (!ratesel.rate) {
+ printk(KERN_DEBUG "%s: Failed to determine TX rate "
+ "for IBSS beacon\n", dev->name);
+ break;
+ }
+ control.vif = &sdata->vif;
+ control.tx_rate = ratesel.rate;
+ if (sdata->bss_conf.use_short_preamble &&
+ ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
+ control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control.flags |= IEEE80211_TXCTL_NO_ACK;
+ control.retry_limit = 1;
+
+ ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
+ if (ifsta->probe_resp) {
+ mgmt = (struct ieee80211_mgmt *)
+ ifsta->probe_resp->data;
+ mgmt->frame_control =
+ IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_PROBE_RESP);
+ } else {
+ printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
+ "template for IBSS\n", dev->name);
+ }
+
+ if (local->ops->beacon_update &&
+ local->ops->beacon_update(local_to_hw(local),
+ skb, &control) == 0) {
+ printk(KERN_DEBUG "%s: Configured IBSS beacon "
+ "template\n", dev->name);
+ skb = NULL;
+ }
+
+ rates = 0;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+ for (j = 0; j < sband->n_bitrates; j++)
+ if (sband->bitrates[j].bitrate == bitrate)
+ rates |= BIT(j);
+ }
+ ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+ } while (0);
+
+ if (skb) {
+ printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
+ "template\n", dev->name);
+ dev_kfree_skb(skb);
+ }
+
+ ifsta->state = IEEE80211_IBSS_JOINED;
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+ ieee80211_rx_bss_put(dev, bss);
+
+ return res;
+}
+
+
static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
size_t len,
@@ -2894,164 +3053,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
return -1;
}

-static int ieee80211_sta_join_ibss(struct net_device *dev,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_sta_bss *bss)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int res, rates, i, j;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_tx_control control;
- struct rate_selection ratesel;
- u8 *pos;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_supported_band *sband;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- /* Remove possible STA entries from other IBSS networks. */
- sta_info_flush(local, NULL);
-
- if (local->ops->reset_tsf) {
- /* Reset own TSF to allow time synchronization work. */
- local->ops->reset_tsf(local_to_hw(local));
- }
- memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
- res = ieee80211_if_config(dev);
- if (res)
- return res;
-
- local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata->drop_unencrypted = bss->capability &
- WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
- res = ieee80211_set_freq(local, bss->freq);
-
- if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
- printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
- "%d MHz\n", dev->name, local->oper_channel->center_freq);
- return -1;
- }
-
- /* Set beacon template based on scan results */
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
- do {
- if (!skb)
- break;
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- mgmt = (struct ieee80211_mgmt *)
- skb_put(skb, 24 + sizeof(mgmt->u.beacon));
- memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
- mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->u.beacon.beacon_int =
- cpu_to_le16(local->hw.conf.beacon_int);
- mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
-
- pos = skb_put(skb, 2 + ifsta->ssid_len);
- *pos++ = WLAN_EID_SSID;
- *pos++ = ifsta->ssid_len;
- memcpy(pos, ifsta->ssid, ifsta->ssid_len);
-
- rates = bss->supp_rates_len;
- if (rates > 8)
- rates = 8;
- pos = skb_put(skb, 2 + rates);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = rates;
- memcpy(pos, bss->supp_rates, rates);
-
- if (bss->band == IEEE80211_BAND_2GHZ) {
- pos = skb_put(skb, 2 + 1);
- *pos++ = WLAN_EID_DS_PARAMS;
- *pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(bss->freq);
- }
-
- pos = skb_put(skb, 2 + 2);
- *pos++ = WLAN_EID_IBSS_PARAMS;
- *pos++ = 2;
- /* FIX: set ATIM window based on scan results */
- *pos++ = 0;
- *pos++ = 0;
-
- if (bss->supp_rates_len > 8) {
- rates = bss->supp_rates_len - 8;
- pos = skb_put(skb, 2 + rates);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = rates;
- memcpy(pos, &bss->supp_rates[8], rates);
- }
-
- memset(&control, 0, sizeof(control));
- rate_control_get_rate(dev, sband, skb, &ratesel);
- if (!ratesel.rate) {
- printk(KERN_DEBUG "%s: Failed to determine TX rate "
- "for IBSS beacon\n", dev->name);
- break;
- }
- control.vif = &sdata->vif;
- control.tx_rate = ratesel.rate;
- if (sdata->bss_conf.use_short_preamble &&
- ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control.flags |= IEEE80211_TXCTL_NO_ACK;
- control.retry_limit = 1;
-
- ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
- if (ifsta->probe_resp) {
- mgmt = (struct ieee80211_mgmt *)
- ifsta->probe_resp->data;
- mgmt->frame_control =
- IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_PROBE_RESP);
- } else {
- printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
- "template for IBSS\n", dev->name);
- }
-
- if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local),
- skb, &control) == 0) {
- printk(KERN_DEBUG "%s: Configured IBSS beacon "
- "template based on scan results\n", dev->name);
- skb = NULL;
- }
-
- rates = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- for (i = 0; i < bss->supp_rates_len; i++) {
- int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < sband->n_bitrates; j++)
- if (sband->bitrates[j].bitrate == bitrate)
- rates |= BIT(j);
- }
- ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
- } while (0);
-
- if (skb) {
- printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
- "template\n", dev->name);
- dev_kfree_skb(skb);
- }
-
- ifsta->state = IEEE80211_IBSS_JOINED;
- mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
-
- ieee80211_rx_bss_put(dev, bss);
-
- return res;
-}
-

static int ieee80211_sta_create_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta)


2008-02-06 02:59:42

by Bruno Randolf

[permalink] [raw]
Subject: Re: [ath5k-devel] [PATCH] addressing johannes latest comments and adding a channel check...

uups, sorry stg mail (well, i...) confused the subject lines

bruno

On Wednesday 06 February 2008 11:46:40 Bruno Randolf wrote:
> mac80211: enable IBSS merging
>
> enable IBSS cell merging. if an IBSS beacon with the same channel, same
> ESSID and a TSF higher than the local TSF (mactime) is received, we have to
> join its BSSID. while this might not be immediately apparent from reading
> the 802.11 standard it is compliant and necessary to make IBSS mode
> functional in many cases. most drivers have a similar behaviour.
>
> * move the relevant code section (previously only containing debug code)
> down to the end of the function, so we can reuse the bss structure.
>
> * we have to compare the mactime (TSF at the time of packet receive) rather
> than the current TSF. since some drivers are not able to give a reliable
> mactime we fall back to use the current TSF, which will be enough to catch
> most (but not all) cases where an IBSS merge is necessary.
>
> * in IBSS mode we want to allow beacons to override probe response info so
> we can correctly do merges.
>
> * we don't only configure beacons based on scan results, so change that
> message.
>
> * to enable this we have to let all beacons thru in IBSS mode, even if they
> have a different BSSID.
>
> Signed-off-by: Bruno Randolf <[email protected]>
> ---
>
> include/net/mac80211.h | 3 +-
> net/mac80211/ieee80211_sta.c | 70
> ++++++++++++++++++++++++++---------------- net/mac80211/rx.c |
> 5 ++-
> 3 files changed, 49 insertions(+), 29 deletions(-)
>
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 460da54..4ae3a12 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -276,7 +276,8 @@ struct ieee80211_tx_control {
> * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
> * the frame.
> * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
> - * is valid.
> + * is valid. This is useful in monitor mode and necessary for beacon
> frames + * to enable IBSS merging.
> */
> enum mac80211_rx_flags {
> RX_FLAG_MMIC_ERROR = 1<<0,
> diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
> index 08f89fa..4df18ae 100644
> --- a/net/mac80211/ieee80211_sta.c
> +++ b/net/mac80211/ieee80211_sta.c
> @@ -2202,7 +2202,7 @@ static void ieee80211_rx_bss_info(struct net_device
> *dev, struct ieee80211_sta_bss *bss;
> struct sta_info *sta;
> struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> - u64 timestamp;
> + u64 timestamp, mactime;
> DECLARE_MAC_BUF(mac);
> DECLARE_MAC_BUF(mac2);
>
> @@ -2220,30 +2220,6 @@ static void ieee80211_rx_bss_info(struct net_device
> *dev, return;
>
> timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
> -
> - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
> - memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
> -#ifdef CONFIG_MAC80211_IBSS_DEBUG
> - static unsigned long last_tsf_debug = 0;
> - u64 tsf;
> - if (local->ops->get_tsf)
> - tsf = local->ops->get_tsf(local_to_hw(local));
> - else
> - tsf = -1LLU;
> - if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
> - 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)tsf,
> - (unsigned long long)timestamp,
> - (unsigned long long)(tsf - timestamp),
> - jiffies);
> - last_tsf_debug = jiffies;
> - }
> -#endif /* CONFIG_MAC80211_IBSS_DEBUG */
> - }
> -
> ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
>
> if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
> @@ -2329,8 +2305,10 @@ static void ieee80211_rx_bss_info(struct net_device
> *dev,
>
> bss->band = rx_status->band;
>
> - if (bss->probe_resp && beacon) {
> - /* Do not allow beacon to override data from Probe Response. */
> + 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;
> }
> @@ -2434,6 +2412,44 @@ static void ieee80211_rx_bss_info(struct net_device
> *dev, 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 &&
> + !local->sta_sw_scanning && !local->sta_hw_scanning &&
> + mgmt->u.beacon.capab_info & 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 */
> + mactime = rx_status->mactime;
> + else if (local && local->ops && local->ops->get_tsf)
> + /* second best option: get current TSF */
> + mactime = local->ops->get_tsf(local_to_hw(local));
> + else
> + /* can't merge without knowing the TSF */
> + mactime = -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)mactime,
> + (unsigned long long)timestamp,
> + (unsigned long long)(mactime - timestamp),
> + jiffies);
> +#endif /* CONFIG_MAC80211_IBSS_DEBUG */
> + if (mactime <= timestamp) {
> + if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit())
> + 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);
> }
>
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index beda1bf..ed7cf37 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1612,7 +1612,10 @@ static int prepare_for_handlers(struct
> ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_IBSS:
> if (!bssid)
> return 0;
> - if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
> + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
> + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
> + return 1;
> + else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
> if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
> return 0;
> rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
>
> _______________________________________________
> ath5k-devel mailing list
> [email protected]
> https://lists.ath5k.org/mailman/listinfo/ath5k-devel



2008-02-06 02:50:08

by Bruno Randolf

[permalink] [raw]
Subject: [PATCH] mac80211: enable IBSS merging

addressing johannes latest comments and adding a channel check...

enable IBSS cell merging. if an IBSS beacon with the same channel, same ESSID
and a TSF higher than the local TSF (mactime) is received, we have to join its
BSSID. while this might not be immediately apparent from reading the 802.11
standard it is compliant and necessary to make IBSS mode functional in many
cases. most drivers have a similar behaviour.

* move the relevant code section (previously only containing debug code) down
to the end of the function, so we can reuse the bss structure.

* we have to compare the mactime (TSF at the time of packet receive) rather
than the current TSF. since some drivers are not able to give a reliable
mactime we fall back to use the current TSF, which will be enough to catch most
(but not all) cases where an IBSS merge is necessary.

* in IBSS mode we want to allow beacons to override probe response info so we
can correctly do merges.

* we don't only configure beacons based on scan results, so change that
message.

* to enable this we have to let all beacons thru in IBSS mode, even if they
have a different BSSID.

Signed-off-by: Bruno Randolf <[email protected]>
---

include/net/mac80211.h | 3 +-
net/mac80211/ieee80211_sta.c | 70 ++++++++++++++++++++++++++----------------
net/mac80211/rx.c | 5 ++-
3 files changed, 49 insertions(+), 29 deletions(-)


diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 460da54..4ae3a12 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -276,7 +276,8 @@ struct ieee80211_tx_control {
* @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
* the frame.
* @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
- * is valid.
+ * is valid. This is useful in monitor mode and necessary for beacon frames
+ * to enable IBSS merging.
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 08f89fa..4df18ae 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2202,7 +2202,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_sta_bss *bss;
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- u64 timestamp;
+ u64 timestamp, mactime;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);

@@ -2220,30 +2220,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
return;

timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
- memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- static unsigned long last_tsf_debug = 0;
- u64 tsf;
- if (local->ops->get_tsf)
- tsf = local->ops->get_tsf(local_to_hw(local));
- else
- tsf = -1LLU;
- if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
- 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)tsf,
- (unsigned long long)timestamp,
- (unsigned long long)(tsf - timestamp),
- jiffies);
- last_tsf_debug = jiffies;
- }
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- }
-
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);

if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
@@ -2329,8 +2305,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,

bss->band = rx_status->band;

- if (bss->probe_resp && beacon) {
- /* Do not allow beacon to override data from Probe Response. */
+ 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;
}
@@ -2434,6 +2412,44 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
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 &&
+ !local->sta_sw_scanning && !local->sta_hw_scanning &&
+ mgmt->u.beacon.capab_info & 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 */
+ mactime = rx_status->mactime;
+ else if (local && local->ops && local->ops->get_tsf)
+ /* second best option: get current TSF */
+ mactime = local->ops->get_tsf(local_to_hw(local));
+ else
+ /* can't merge without knowing the TSF */
+ mactime = -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)mactime,
+ (unsigned long long)timestamp,
+ (unsigned long long)(mactime - timestamp),
+ jiffies);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ if (mactime <= timestamp) {
+ if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit())
+ 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);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index beda1bf..ed7cf37 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1612,7 +1612,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
case IEEE80211_IF_TYPE_IBSS:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+ return 1;
+ else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
return 0;
rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;