mac80211: IBSS supported rate fixes

Currently mac80211 announces a rate set with no basic rates,
this fixes it to use 1/2 or 6/9 Mbit as basic rates by default.
Additionally, mac80211 will currently adopt the peer's entire
rate set, rather than just the basic rate set; fix that too.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c94a695..c236079 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -63,19 +63,18 @@
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				      const u8 *bssid, const int beacon_int,
 				      struct ieee80211_channel *chan,
-				      const size_t supp_rates_len,
-				      const u8 *supp_rates,
+				      const u32 basic_rates,
 				      const u16 capability, u64 tsf)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
-	int rates, i, j;
+	int rates, i;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
 	struct ieee80211_supported_band *sband;
 	u32 bss_change;
-
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 
 	/* Reset own TSF to allow time synchronization work. */
 	drv_reset_tsf(local);
@@ -101,6 +100,16 @@
 
 	sband = local->hw.wiphy->bands[chan->band];
 
+	/* build supported rates array */
+	pos = supp_rates;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		int rate = sband->bitrates[i].bitrate;
+		u8 basic = 0;
+		if (basic_rates & BIT(i))
+			basic = 0x80;
+		*pos++ = basic | (u8) (rate / 5);
+	}
+
 	/* Build IBSS probe response */
 	mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 	memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
@@ -118,7 +127,7 @@
 	*pos++ = ifibss->ssid_len;
 	memcpy(pos, ifibss->ssid, ifibss->ssid_len);
 
-	rates = supp_rates_len;
+	rates = sband->n_bitrates;
 	if (rates > 8)
 		rates = 8;
 	pos = skb_put(skb, 2 + rates);
@@ -140,8 +149,8 @@
 	*pos++ = 0;
 	*pos++ = 0;
 
-	if (supp_rates_len > 8) {
-		rates = supp_rates_len - 8;
+	if (sband->n_bitrates > 8) {
+		rates = sband->n_bitrates - 8;
 		pos = skb_put(skb, 2 + rates);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
 		*pos++ = rates;
@@ -162,15 +171,7 @@
 	bss_change |= BSS_CHANGED_BEACON_ENABLED;
 	ieee80211_bss_info_change_notify(sdata, bss_change);
 
-	rates = 0;
-	for (i = 0; i < supp_rates_len; i++) {
-		int bitrate = (supp_rates[i] & 0x7f) * 5;
-		for (j = 0; j < sband->n_bitrates; j++)
-			if (sband->bitrates[j].bitrate == bitrate)
-				rates |= BIT(j);
-	}
-
-	ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
+	ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
 
 	ifibss->state = IEEE80211_IBSS_MLME_JOINED;
 	mod_timer(&ifibss->timer,
@@ -184,15 +185,35 @@
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_bss *bss)
 {
+	struct ieee80211_supported_band *sband;
+	u32 basic_rates;
+	int i, j;
 	u16 beacon_int = bss->cbss.beacon_interval;
 
 	if (beacon_int < 10)
 		beacon_int = 10;
 
+	sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
+
+	basic_rates = 0;
+
+	for (i = 0; i < bss->supp_rates_len; i++) {
+		int rate = (bss->supp_rates[i] & 0x7f) * 5;
+		bool is_basic = !!(bss->supp_rates[i] & 0x80);
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate) {
+				if (is_basic)
+					basic_rates |= BIT(j);
+				break;
+			}
+		}
+	}
+
 	__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
 				  beacon_int,
 				  bss->cbss.channel,
-				  bss->supp_rates_len, bss->supp_rates,
+				  basic_rates,
 				  bss->cbss.capability,
 				  bss->cbss.tsf);
 }
@@ -449,9 +470,7 @@
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
-	u8 *pos;
 	u8 bssid[ETH_ALEN];
-	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	u16 capability;
 	int i;
 
@@ -480,15 +499,9 @@
 	else
 		sdata->drop_unencrypted = 0;
 
-	pos = supp_rates;
-	for (i = 0; i < sband->n_bitrates; i++) {
-		int rate = sband->bitrates[i].bitrate;
-		*pos++ = (u8) (rate / 5);
-	}
-
 	__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
-				  ifibss->channel, sband->n_bitrates,
-				  supp_rates, capability, 0);
+				  ifibss->channel, 3, /* first two are basic */
+				  capability, 0);
 }
 
 static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)