Patchwork [RFC,2/3] wpa_supplicant: Add 2040 BSS intolerance support in station mode

login
register
mail settings
Submitter Jouni Malinen
Date April 23, 2012, 9:01 a.m.
Message ID <20120423090107.GB6369@w1.fi>
Download mbox | patch
Permalink /patch/154353/
State Superseded
Headers show

Comments

Jouni Malinen - April 23, 2012, 9:01 a.m.
On Wed, Apr 18, 2012 at 07:14:09PM +0530, Rajkumar Manoharan wrote:
> Add support for HT STA to report 40MHz intolerance to the associated AP.
> A HT station generates a report (2040 BSS coexistence) of channel list
> if it finds a non-HT capable AP or a HT AP which prohibits 40MHz
> transmission (i.e 40MHz intolerant bit is set in HT capabilities IE)
> from the scan results.

This looks SME-specific, so it would be cleaner to keep the
implementation within sme.c until some other uses show up for it. The
below version does that and adds couple of TODO/FIX comments that should
be addressed. The OBSS scan one could be left as a separate one for now,
but the other comments should be addressed for the initial commit (well,
apart from the special Country element cases with operating class
triplets).
Rajkumar Manoharan - April 23, 2012, 11:11 a.m.
On Mon, Apr 23, 2012 at 12:01:07PM +0300, Jouni Malinen wrote:
> On Wed, Apr 18, 2012 at 07:14:09PM +0530, Rajkumar Manoharan wrote:
> > Add support for HT STA to report 40MHz intolerance to the associated AP.
> > A HT station generates a report (2040 BSS coexistence) of channel list
> > if it finds a non-HT capable AP or a HT AP which prohibits 40MHz
> > transmission (i.e 40MHz intolerant bit is set in HT capabilities IE)
> > from the scan results.
> 
> This looks SME-specific, so it would be cleaner to keep the
> implementation within sme.c until some other uses show up for it. The
> below version does that and adds couple of TODO/FIX comments that should
> be addressed. The OBSS scan one could be left as a separate one for now,
> but the other comments should be addressed for the initial commit (well,
> apart from the special Country element cases with operating class
> triplets).
> 
> 
Thanks a lot for the cleanup patch.

> diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> index da9cf2b..f6e1622 100644
> --- a/wpa_supplicant/events.c
> +++ b/wpa_supplicant/events.c
> @@ -1096,6 +1096,12 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
>  
>  	selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
>  
> +	/*
> +	 * TODO: This should be done at the completion of OBSS scan operations
> +	 * which may or may not be identical to other scans..
> +	 */
> +	sme_proc_40mhz_intolerant(wpa_s);
> +
>  	if (selected) {
>  		int skip;
>  		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
> diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
> index b366847..f4aa006 100644
> --- a/wpa_supplicant/sme.c
> +++ b/wpa_supplicant/sme.c
> @@ -609,6 +609,160 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
>  }
>  
>  
> +static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
> +				   const u8 *chan_list, u8 num_channels)
> +{
> +	struct ieee80211_2040_bss_coex_ie *bc_ie;
> +	struct ieee80211_2040_intol_chan_report *ic_report;
> +	struct wpabuf *buf;
> +
> +	wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
> +		   MAC2STR(wpa_s->bssid));
> +
> +	buf = wpabuf_alloc(2 + /* action.category + action_code */
> +			   sizeof(struct ieee80211_2040_bss_coex_ie) +
> +			   sizeof(struct ieee80211_2040_intol_chan_report) +
> +			   num_channels);
> +	if (buf == NULL)
> +		return;
> +
> +	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
> +	wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
> +
> +	bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
> +	bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
> +	bc_ie->length = 1;
> +	/* TODO: is this flag really supposed to be added uncontionally?
> +	 * Shouldn't this be added onyl if a trigger event TE-B has been
> +	 * detected?
> +	 */
> +	bc_ie->coex_info = WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
> +
> +	ic_report = wpabuf_put(buf, sizeof(*ic_report));
> +	ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
> +	ic_report->length = num_channels + 1;
> +	/* FIX: set ic_report->op_class */
> +
As mentioned in TODO, op_class is set as "unknown" as regulatory triplet is not
handled. So that ic_report->op_class is 0 and it is not explicitly mentioned.

> +	os_memcpy(wpabuf_put(buf, num_channels), chan_list, num_channels);
> +
> +	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
> +				wpa_s->own_addr, wpa_s->bssid,
> +				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
> +		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send 20/40 BSS "
> +			"Coexistence frame");
> +	}
> +
> +	wpabuf_free(buf);
> +}
> +
> +
> +	/*
> +	 * Check whether AP uses regulatory triplet or channel triplet in
> +	 * country info. Right now the operating class of the BSS channel
> +	 * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
> +	 * based on the assumption that operating class triplet is not used in
> +	 * beacon frame. If the First Channel Number/Operating Extension
> +	 * Identifier octet has a positive integer value of 201 or greater,
> +	 * then its operating class triplet.
> +	 *
> +	 * TODO: If Supported Operating Classes element is present in Beacon
> +	 * frame, have to lookup operating class in Annex E and fill them in
> +	 * 20/40 coex frame.
> +	 *
> +	 * TODO: Is it fine to skip this report if Country element is not
> +	 * included?
> +	 */
It is only be ignored if first channel number in country IE is >= 201. 
If so, then the triplet comprises operating class set that we are not taking
care right now. Do you still want to consider those IEs?

> +	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
> +	if (!ie || ie[1] < 6 || (ie[5] > 201))
> +		return;
> +
-Rajkumar
Rajkumar Manoharan - April 23, 2012, 11:28 a.m.
On Mon, Apr 23, 2012 at 04:41:49PM +0530, Rajkumar Manoharan wrote:
> On Mon, Apr 23, 2012 at 12:01:07PM +0300, Jouni Malinen wrote:
> > On Wed, Apr 18, 2012 at 07:14:09PM +0530, Rajkumar Manoharan wrote:
> > > Add support for HT STA to report 40MHz intolerance to the associated AP.
> > > A HT station generates a report (2040 BSS coexistence) of channel list
> > > if it finds a non-HT capable AP or a HT AP which prohibits 40MHz
> > > transmission (i.e 40MHz intolerant bit is set in HT capabilities IE)
> > > from the scan results.
> > 
> > This looks SME-specific, so it would be cleaner to keep the
> > implementation within sme.c until some other uses show up for it. The
> > below version does that and adds couple of TODO/FIX comments that should
> > be addressed. The OBSS scan one could be left as a separate one for now,
> > but the other comments should be addressed for the initial commit (well,
> > apart from the special Country element cases with operating class
> > triplets).
> > 
> > 
> Thanks a lot for the cleanup patch.
> 
> > diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> > index da9cf2b..f6e1622 100644
> > --- a/wpa_supplicant/events.c
> > +++ b/wpa_supplicant/events.c
> > @@ -1096,6 +1096,12 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
> >  
> >  	selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
> >  
> > +	/*
> > +	 * TODO: This should be done at the completion of OBSS scan operations
> > +	 * which may or may not be identical to other scans..
> > +	 */
> > +	sme_proc_40mhz_intolerant(wpa_s);
> > +
> >  	if (selected) {
> >  		int skip;
> >  		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
> > diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
> > index b366847..f4aa006 100644
> > --- a/wpa_supplicant/sme.c
> > +++ b/wpa_supplicant/sme.c
> > @@ -609,6 +609,160 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
> >  }
> >  
> >  
> > +static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
> > +				   const u8 *chan_list, u8 num_channels)
> > +{
> > +	struct ieee80211_2040_bss_coex_ie *bc_ie;
> > +	struct ieee80211_2040_intol_chan_report *ic_report;
> > +	struct wpabuf *buf;
> > +
> > +	wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
> > +		   MAC2STR(wpa_s->bssid));
> > +
> > +	buf = wpabuf_alloc(2 + /* action.category + action_code */
> > +			   sizeof(struct ieee80211_2040_bss_coex_ie) +
> > +			   sizeof(struct ieee80211_2040_intol_chan_report) +
> > +			   num_channels);
> > +	if (buf == NULL)
> > +		return;
> > +
> > +	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
> > +	wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
> > +
> > +	bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
> > +	bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
> > +	bc_ie->length = 1;
> > +	/* TODO: is this flag really supposed to be added uncontionally?
> > +	 * Shouldn't this be added onyl if a trigger event TE-B has been
> > +	 * detected?
> > +	 */
> > +	bc_ie->coex_info = WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
> > +
> > +	ic_report = wpabuf_put(buf, sizeof(*ic_report));
> > +	ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
> > +	ic_report->length = num_channels + 1;
> > +	/* FIX: set ic_report->op_class */
> > +
> As mentioned in TODO, op_class is set as "unknown" as regulatory triplet is not
> handled. So that ic_report->op_class is 0 and it is not explicitly mentioned.
> 
> > +	os_memcpy(wpabuf_put(buf, num_channels), chan_list, num_channels);
> > +
> > +	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
> > +				wpa_s->own_addr, wpa_s->bssid,
> > +				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
> > +		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send 20/40 BSS "
> > +			"Coexistence frame");
> > +	}
> > +
> > +	wpabuf_free(buf);
> > +}
> > +
> > +
> > +	/*
> > +	 * Check whether AP uses regulatory triplet or channel triplet in
> > +	 * country info. Right now the operating class of the BSS channel
> > +	 * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
> > +	 * based on the assumption that operating class triplet is not used in
> > +	 * beacon frame. If the First Channel Number/Operating Extension
> > +	 * Identifier octet has a positive integer value of 201 or greater,
> > +	 * then its operating class triplet.
> > +	 *
> > +	 * TODO: If Supported Operating Classes element is present in Beacon
> > +	 * frame, have to lookup operating class in Annex E and fill them in
> > +	 * 20/40 coex frame.
> > +	 *
> > +	 * TODO: Is it fine to skip this report if Country element is not
> > +	 * included?
> > +	 */
> It is only be ignored if first channel number in country IE is >= 201. 
> If so, then the triplet comprises operating class set that we are not taking
> care right now. Do you still want to consider those IEs?
> 
correction. I should change the condition as well.
> > +	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
> > +	if (!ie || ie[1] < 6 || (ie[5] > 201))
> > +		return;
> > +
-Rajkumar

Patch

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index da9cf2b..f6e1622 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1096,6 +1096,12 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
 	selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
 
+	/*
+	 * TODO: This should be done at the completion of OBSS scan operations
+	 * which may or may not be identical to other scans..
+	 */
+	sme_proc_40mhz_intolerant(wpa_s);
+
 	if (selected) {
 		int skip;
 		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index b366847..f4aa006 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -609,6 +609,160 @@  void sme_deinit(struct wpa_supplicant *wpa_s)
 }
 
 
+static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+				   const u8 *chan_list, u8 num_channels)
+{
+	struct ieee80211_2040_bss_coex_ie *bc_ie;
+	struct ieee80211_2040_intol_chan_report *ic_report;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+		   MAC2STR(wpa_s->bssid));
+
+	buf = wpabuf_alloc(2 + /* action.category + action_code */
+			   sizeof(struct ieee80211_2040_bss_coex_ie) +
+			   sizeof(struct ieee80211_2040_intol_chan_report) +
+			   num_channels);
+	if (buf == NULL)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+	bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+	bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+	bc_ie->length = 1;
+	/* TODO: is this flag really supposed to be added uncontionally?
+	 * Shouldn't this be added onyl if a trigger event TE-B has been
+	 * detected?
+	 */
+	bc_ie->coex_info = WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+	ic_report = wpabuf_put(buf, sizeof(*ic_report));
+	ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+	ic_report->length = num_channels + 1;
+	/* FIX: set ic_report->op_class */
+
+	os_memcpy(wpabuf_put(buf, num_channels), chan_list, num_channels);
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send 20/40 BSS "
+			"Coexistence frame");
+	}
+
+	wpabuf_free(buf);
+}
+
+
+/**
+ * enum wpas_band - Frequency band
+ * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
+ * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum wpas_band {
+	WPAS_BAND_2GHZ,
+	WPAS_BAND_5GHZ,
+	WPAS_BAND_INVALID
+};
+
+/**
+ * freq_to_channel - Convert frequency into channel info
+ * @channel: Buffer for returning channel number
+ * Returns: Band (2 or 5 GHz)
+ */
+static enum wpas_band freq_to_channel(int freq, u8 *channel)
+{
+	enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
+	u8 chan = 0;
+
+	if (freq >= 2412 && freq <= 2472)
+		chan = (freq - 2407) / 5;
+	else if (freq == 2484)
+		chan = 14;
+	else if (freq >= 5180 && freq <= 5805)
+		chan = (freq - 5000) / 5;
+
+	*channel = chan;
+	return band;
+}
+
+
+void sme_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	enum wpas_band assoc_band;
+	const u8 *ie;
+	u16 ht_cap;
+	u8 chan_list[P2P_MAX_CHANNELS], channel;
+	u8 num_channels = 0, i;
+
+	if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+		return;
+
+	/* Check whether local driver supports HT40 */
+	if (!wpa_s->hw.modes ||
+	    !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+		return;
+
+	/* Check whether AP supports HT40 */
+	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+	if (!ie || ie[1] < 2 ||
+	    !(ie[3] & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH))
+		return;
+
+	/*
+	 * Check whether AP uses regulatory triplet or channel triplet in
+	 * country info. Right now the operating class of the BSS channel
+	 * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
+	 * based on the assumption that operating class triplet is not used in
+	 * beacon frame. If the First Channel Number/Operating Extension
+	 * Identifier octet has a positive integer value of 201 or greater,
+	 * then its operating class triplet.
+	 *
+	 * TODO: If Supported Operating Classes element is present in Beacon
+	 * frame, have to lookup operating class in Annex E and fill them in
+	 * 20/40 coex frame.
+	 *
+	 * TODO: Is it fine to skip this report if Country element is not
+	 * included?
+	 */
+	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+	if (!ie || ie[1] < 6 || (ie[5] > 201))
+		return;
+
+	assoc_band = freq_to_channel(wpa_s->current_bss->freq, &channel);
+	os_memset(chan_list, 0, sizeof(chan_list));
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		/* Skip other band bss */
+		if (freq_to_channel(bss->freq, &channel) != assoc_band)
+			continue;
+
+		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+		ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+		/* TODO: Shouldn't TE-B events be counted separately so that
+		 * 20 MHz width request flag can be set correctly? */
+		if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+			/* Check whether the channel is already considered */
+			for (i = 0; i < num_channels; i++) {
+				if (channel == chan_list[i])
+					break;
+			}
+			if (i != num_channels)
+				continue;
+
+			chan_list[num_channels++] = channel;
+		}
+	}
+
+	if (num_channels)
+		sme_send_2040_bss_coex(wpa_s, chan_list, num_channels);
+}
+
+
 #ifdef CONFIG_IEEE80211W
 
 static const unsigned int sa_query_max_timeout = 1000;
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 33530bb..f735832 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -35,6 +35,8 @@  void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
 				       const u8 *prev_pending_bssid);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
+void sme_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+
 #else /* CONFIG_SME */
 
 static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -95,6 +97,10 @@  static inline void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 }
 
+static inline void sme_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s)
+{
+}
+
 #endif /* CONFIG_SME */
 
 #endif /* SME_H */