diff mbox

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

Message ID 20120423090107.GB6369@w1.fi
State Superseded
Headers show

Commit Message

Jouni Malinen April 23, 2012, 9:01 a.m. UTC
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).

Comments

Rajkumar Manoharan April 23, 2012, 11:11 a.m. UTC | #1
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. UTC | #2
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
diff mbox

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 */