Search Linux Wireless

[PATCH] ath9k: Handle channel initialization for AP mode

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

 



Hostapd now passes the HT parameters through the config()
callback, use these to set the appropriate channel in AP mode.

Signed-off-by: Sujith <Sujith.Manoharan@xxxxxxxxxxx>
---
Note: This patch depends on [PATCHv2] nl80211: Add frequency configuration (including HT40)
posted by Jouni.

 drivers/net/wireless/ath9k/main.c |   60 ++++++++++++++++++++++++++----------
 drivers/net/wireless/ath9k/rc.c   |   55 +++++++++++++++++++++++++++++----
 2 files changed, 91 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 6e103d5..d1ddb07 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -622,35 +622,35 @@ static int ath_get_channel(struct ath_softc *sc,
 	return -1;
 }
 
+/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
+
 static u32 ath_get_extchanmode(struct ath_softc *sc,
 			       struct ieee80211_channel *chan,
-			       struct ieee80211_bss_conf *bss_conf)
+			       int ext_chan_offset,
+			       enum ath9k_ht_macmode tx_chan_width)
 {
 	u32 chanmode = 0;
-	u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset;
-	enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ?
-		ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
 
 	switch (chan->band) {
 	case IEEE80211_BAND_2GHZ:
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+		if ((ext_chan_offset == 0) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_20))
 			chanmode = CHANNEL_G_HT20;
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+		if ((ext_chan_offset == 1) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
 			chanmode = CHANNEL_G_HT40PLUS;
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+		if ((ext_chan_offset == -1) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
 			chanmode = CHANNEL_G_HT40MINUS;
 		break;
 	case IEEE80211_BAND_5GHZ:
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+		if ((ext_chan_offset == 0) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_20))
 			chanmode = CHANNEL_A_HT20;
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+		if ((ext_chan_offset == 1) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
 			chanmode = CHANNEL_A_HT40PLUS;
-		if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+		if ((ext_chan_offset == -1) &&
 		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
 			chanmode = CHANNEL_A_HT40MINUS;
 		break;
@@ -841,6 +841,18 @@ static void ath9k_ht_conf(struct ath_softc *sc,
 	}
 }
 
+static inline int ath_sec_offset(u8 ext_offset)
+{
+	if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
+		return 0;
+	else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
+		return 1;
+	else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
+		return -1;
+
+	return 0;
+}
+
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
@@ -893,13 +905,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
 		}
 
 		if (hw->conf.ht.enabled) {
-			sc->sc_ah->ah_channels[pos].chanmode =
-				ath_get_extchanmode(sc, curchan, bss_conf);
+			int offset =
+				ath_sec_offset(bss_conf->ht.secondary_channel_offset);
+			sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
+				ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
 
-			if (bss_conf->ht.width_40_ok)
-				sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
-			else
-				sc->tx_chan_width = ATH9K_HT_MACMODE_20;
+			sc->sc_ah->ah_channels[pos].chanmode =
+				ath_get_extchanmode(sc, curchan,
+						    offset, sc->tx_chan_width);
 		} else {
 			sc->sc_ah->ah_channels[pos].chanmode =
 				(curchan->band == IEEE80211_BAND_2GHZ) ?
@@ -2172,9 +2185,22 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 			(curchan->band == IEEE80211_BAND_2GHZ) ?
 			CHANNEL_G : CHANNEL_A;
 
-		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+		if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) &&
+		    (conf->ht.enabled)) {
+			sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
+				ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
+
+			sc->sc_ah->ah_channels[pos].chanmode =
+				ath_get_extchanmode(sc, curchan,
+						    conf->ht.sec_chan_offset,
+						    sc->tx_chan_width);
+		}
+
+		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: Unable to set channel\n", __func__);
+			return -EINVAL;
+		}
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_HT)
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index 93dfea8..7c08583 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -1304,6 +1304,38 @@ static void ath_rc_tx_status(struct ath_softc *sc,
 			 xretries, long_retry);
 }
 
+static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
+						    enum ieee80211_band band,
+						    bool is_ht, bool is_cw_40)
+{
+	int mode = 0;
+
+	switch(band) {
+	case IEEE80211_BAND_2GHZ:
+		mode = ATH9K_MODE_11G;
+		if (is_ht)
+			mode = ATH9K_MODE_11NG_HT20;
+		if (is_cw_40)
+			mode = ATH9K_MODE_11NG_HT40PLUS;
+		break;
+	case IEEE80211_BAND_5GHZ:
+		mode = ATH9K_MODE_11A;
+		if (is_ht)
+			mode = ATH9K_MODE_11NA_HT20;
+		if (is_cw_40)
+			mode = ATH9K_MODE_11NA_HT40PLUS;
+		break;
+	default:
+		DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n");
+		return NULL;
+	}
+
+	BUG_ON(mode >= ATH9K_MODE_MAX);
+
+	DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode);
+	return sc->hw_rate_table[mode];
+}
+
 static void ath_rc_init(struct ath_softc *sc,
 			struct ath_rate_priv *ath_rc_priv,
 			struct ieee80211_supported_band *sband,
@@ -1314,16 +1346,25 @@ static void ath_rc_init(struct ath_softc *sc,
 	u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
 	u8 i, j, k, hi = 0, hthi = 0;
 
-	rate_table = sc->hw_rate_table[sc->sc_curmode];
+	/* FIXME: Adhoc */
+	if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
+	    (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) {
+		bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		rate_table = ath_choose_rate_table(sc, sband->band,
+						   sta->ht_cap.ht_supported,
+						   is_cw_40);
+	} else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+		/* sc_curmode would be set on init through config() */
+		rate_table = sc->hw_rate_table[sc->sc_curmode];
+	}
 
-	if (sta->ht_cap.ht_supported) {
-		if (sband->band == IEEE80211_BAND_2GHZ)
-			rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
-		else
-			rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
+	if (!rate_table) {
+		DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+		return;
+	}
 
+	if (sta->ht_cap.ht_supported) {
 		ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
-
 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 			ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
 	}
-- 
1.6.0.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[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