From: John W. Linville <linville@redhat.com> Date: Thu, 6 Nov 2008 14:28:58 -0500 Subject: [wireless] iwlagn/mac80211 IBSS fixes Message-id: 20081106192857.GD16276@redhat.com O-Subject: [RHEL5.3 PATCH] iwlagn/mac80211 IBSS fixes Bugzilla: 438388 RH-Acked-by: Andy Gospodarek <gospo@redhat.com> The iwlagn/mac80211 combination in current RHEL5 kernels is non-functional for IBSS (aka "Ad-Hoc") mode. BZ438388 This includes a fix to handle beacon setup as well as a number of IBSS-related fixes backported from upstream as detailed below. commit 9818babc8fd9a542978a235f1c1786f948cbac68 Author: Tomas Winkler <tomas.winkler@intel.com> Date: Wed Sep 3 23:42:19 2008 +0300 mac80211: Fix low bit rate in IBSS This patch fixes regression in iwlwifi IBSS rate scaling caused by patch: commit 6bc37c06bc424bcf3f944e6a79e2d5bb537e02ed Author: Vladimir Koutny <vlado@work.ksp.sk> Date: Fri Jun 13 16:50:44 2008 +0200 mac80211: eliminate IBSS warning in rate_lowest_index() An IBSS station is added in prepare_for_handlers where the rate scaling was initialized only with single rate matching the received packet. The correct rate scale information should be updated only in ieee80211_rx_bss_info function where beacon is parsed. Because of coding error the rate info was left untouched. If a beacon has triggered the connection the rate remined 1Mbps. This patch fixes this coding error Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Cc: Vladimir Koutny <vlado@work.ksp.sk> Signed-off-by: John W. Linville <linville@tuxdriver.com> commit 80693ceb78b08baa3b66a900d9225b2cf9c6f0ed Author: Daniel Drake <dsd@gentoo.org> Date: Sat Jul 19 23:31:17 2008 +0100 mac80211: automatic IBSS channel selection When joining an ad-hoc network, the user is currently required to specify the channel. The network will not be joined otherwise, unless it happens to be sitting on the currently active channel. This patch implements automatic channel selection when the user has not locked the interface onto a specific channel. Signed-off-by: Daniel Drake <dsd@gentoo.org> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> commit 1e188637902eb4b62d325d3cc76b076724f3ec55 Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Date: Thu Jul 10 17:54:14 2008 +0300 mac80211: dont add a STA which is not in the same IBSS This patch avoids adding STAs that don't belong to our IBSS ieee80211_bssid_match matches also bcast address so also APs were added Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> commit 87291c0269e77b029282676448fed3706a54211a Author: Vladimir Koutny <vlado@work.ksp.sk> Date: Fri Jun 13 16:50:44 2008 +0200 mac80211: eliminate IBSS warning in rate_lowest_index() In IBSS mode prior to join/creation of new IBSS it is possible that a frame from unknown station is received and an ibss_add_sta() is called. This will cause a warning in rate_lowest_index() since the list of supported rates of our station is not initialized yet. The fix is to add ibss stations with a rate we received that frame at; this single-element set will be extended later based on beacon data. Also there is no need to store stations from a foreign IBSS. Signed-off-by: Vladimir Koutny <vlado@ksp.sk> Signed-off-by: John W. Linville <linville@tuxdriver.com> Intel test team confirms proper IBSS operation with my test kernels. John diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4178018..b85b1cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2960,10 +2960,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } -#if 0 /* Not in RHEL5 */ /* temporary */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); -#endif +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control); static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -3559,8 +3558,8 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -#if 0 /* Not in RHEL5 */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) { struct iwl_priv *priv = hw->priv; unsigned long flags; @@ -3603,7 +3602,6 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return 0; } -#endif /***************************************************************************** * @@ -4161,6 +4159,7 @@ static struct ieee80211_ops iwl4965_hw_ops = { .get_tx_stats = iwl4965_mac_get_tx_stats, .conf_tx = iwl4965_mac_conf_tx, .reset_tsf = iwl4965_mac_reset_tsf, + .beacon_update = iwl4965_mac_beacon_update, .bss_info_changed = iwl4965_bss_info_changed, .ampdu_action = iwl4965_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 83d9927..81dde16 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -922,7 +922,7 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct sk_buff *skb, u8 *bssid, - u8 *addr); + u8 *addr, u64 supp_rates); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c6c9e47..cb91e08 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2577,7 +2577,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, rx_status->band); prev_rates = sta->supp_rates[rx_status->band]; - sta->supp_rates[rx_status->band] &= supp_rates; + 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 @@ -2834,7 +2834,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, 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); + mgmt->bssid, mgmt->sa, + BIT(rx_status->rate_idx)); } } @@ -3618,11 +3619,21 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len))) { + + if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { int ret; + int search_freq; + + if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) + search_freq = bss->freq; + else + search_freq = local->hw.conf.channel->center_freq; + + bss = ieee80211_rx_bss_get(dev, bssid, search_freq, + ifsta->ssid, ifsta->ssid_len); + if (!bss) + goto dont_join; + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", dev->name, print_mac(mac, bssid)); @@ -3630,6 +3641,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, ieee80211_rx_bss_put(dev, bss); return ret; } + +dont_join: #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG " did not try to join ibss\n"); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ @@ -4269,12 +4282,13 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct sk_buff *skb, u8 *bssid, - u8 *addr) + u8 *addr, u64 supp_rates) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); DECLARE_MAC_BUF(mac); + int band = local->hw.conf.channel->band; /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ @@ -4286,6 +4300,9 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, return NULL; } + if (compare_ether_addr(bssid, sdata->u.sta.bssid)) + return NULL; + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); @@ -4295,8 +4312,10 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, sta->flags |= WLAN_STA_AUTHORIZED; - sta->supp_rates[local->hw.conf.channel->band] = - sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; + if (supp_rates) + sta->supp_rates[band] = supp_rates; + else + sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band]; rate_control_rate_init(sta, local); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0ab0c50..12ea72e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1806,8 +1806,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!bssid) return 0; if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { + if (!rx->sta) + rx->sta = ieee80211_ibss_add_sta(sdata->dev, + rx->skb, bssid, hdr->addr2, + BIT(rx->status->rate_idx)); return 1; + } else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; @@ -1820,7 +1825,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, - bssid, hdr->addr2); + bssid, hdr->addr2, + BIT(rx->status->rate_idx)); break; case IEEE80211_IF_TYPE_MESH_POINT: if (!multicast &&