Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3848

kernel-2.6.18-194.11.1.el5.src.rpm

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 &&