Message ID | 20120423090107.GB6369@w1.fi |
---|---|
State | Superseded |
Headers | show |
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
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 --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 */