Пример #1
0
void hostapd_2040_coex_action(struct hostapd_data *hapd,
			      const struct ieee80211_mgmt *mgmt, size_t len)
{
	struct hostapd_iface *iface = hapd->iface;
	struct ieee80211_2040_bss_coex_ie *bc_ie;
	struct ieee80211_2040_intol_chan_report *ic_report;
	int is_ht40_allowed = 1;
	int i;
	const u8 *start = (const u8 *) mgmt;
	const u8 *data = start + IEEE80211_HDRLEN + 2;

	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
		       mgmt->u.action.u.public_action.action);

	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
		return;

	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
		return;

	bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
	if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
	    bc_ie->length < 1) {
		wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
			   bc_ie->element_id, bc_ie->length);
		return;
	}
	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
		return;
	data += 2 + bc_ie->length;

	wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
		   bc_ie->coex_param);
	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "20 MHz BSS width request bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "40 MHz intolerant bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	if (start + len - data >= 3 &&
	    data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
		u8 ielen = data[1];

		if (ielen > start + len - data - 2)
			return;
		ic_report = (struct ieee80211_2040_intol_chan_report *) data;
		wpa_printf(MSG_DEBUG,
			   "20/40 BSS Intolerant Channel Report: Operating Class %u",
			   ic_report->op_class);

		/* Go through the channel report to find any BSS there in the
		 * affected channel range */
		for (i = 0; i < ielen - 1; i++) {
			u8 chan = ic_report->variable[i];

			if (is_40_allowed(iface, chan))
				continue;
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_DEBUG,
				       "20_40_INTOLERANT channel %d reported",
				       chan);
			is_ht40_allowed = 0;
		}
	}
	wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
		   is_ht40_allowed, iface->num_sta_ht40_intolerant);

	if (!is_ht40_allowed &&
	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
		if (iface->conf->secondary_channel) {
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_INFO,
				       "Switching to 20 MHz operation");
			iface->conf->secondary_channel = 0;
			ieee802_11_set_beacons(iface);
		}
		if (!iface->num_sta_ht40_intolerant &&
		    iface->conf->obss_interval) {
			unsigned int delay_time;
			delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
				iface->conf->obss_interval;
			eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
					     NULL);
			eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
					       hapd->iface, NULL);
			wpa_printf(MSG_DEBUG,
				   "Reschedule HT 20/40 timeout to occur in %u seconds",
				   delay_time);
		}
	}
}
Пример #2
0
void hostapd_2040_coex_action(struct hostapd_data *hapd,
			      const struct ieee80211_mgmt *mgmt, size_t len)
{
	struct hostapd_iface *iface = hapd->iface;
	struct ieee80211_2040_bss_coex_ie *bc_ie;
	struct ieee80211_2040_intol_chan_report *ic_report;
	int is_ht40_allowed = 1;
	int i;
	const u8 *start = (const u8 *) mgmt;
	const u8 *data = start + IEEE80211_HDRLEN + 2;
	struct sta_info *sta;

	wpa_printf(MSG_DEBUG,
		   "HT: Received 20/40 BSS Coexistence Management frame from "
		   MACSTR, MAC2STR(mgmt->sa));

	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
		       mgmt->u.action.u.public_action.action);

	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
		wpa_printf(MSG_DEBUG,
			   "Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
		return;
	}

	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
		wpa_printf(MSG_DEBUG,
			   "Ignore too short 20/40 BSS Coexistence Management frame");
		return;
	}

	/* 20/40 BSS Coexistence element */
	bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
	if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
	    bc_ie->length < 1) {
		wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
			   bc_ie->element_id, bc_ie->length);
		return;
	}
	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
		wpa_printf(MSG_DEBUG,
			   "Truncated 20/40 BSS Coexistence element");
		return;
	}
	data += 2 + bc_ie->length;

	wpa_printf(MSG_DEBUG,
		   "20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
		   bc_ie->coex_param,
		   (bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
		   (bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
		   (bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
		   (bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
		   (bc_ie->coex_param & BIT(4)) ?
		   "[OBSSScanExemptionGrant]" : "",
		   (bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
		   "[Reserved]" : "");

	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
		/* Intra-BSS communication prohibiting 20/40 MHz BSS operation
		 */
		sta = ap_get_sta(hapd, mgmt->sa);
		if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
			wpa_printf(MSG_DEBUG,
				   "Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
			return;
		}

		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "20 MHz BSS width request bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
		/* Inter-BSS communication prohibiting 20/40 MHz BSS operation
		 */
		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "40 MHz intolerant bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	/* 20/40 BSS Intolerant Channel Report element (zero or more times) */
	while (start + len - data >= 3 &&
	       data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
		u8 ielen = data[1];

		if (ielen > start + len - data - 2) {
			wpa_printf(MSG_DEBUG,
				   "Truncated 20/40 BSS Intolerant Channel Report element");
			return;
		}
		ic_report = (struct ieee80211_2040_intol_chan_report *) data;
		wpa_printf(MSG_DEBUG,
			   "20/40 BSS Intolerant Channel Report: Operating Class %u",
			   ic_report->op_class);

		/* Go through the channel report to find any BSS there in the
		 * affected channel range */
		for (i = 0; i < ielen - 1; i++) {
			u8 chan = ic_report->variable[i];

			if (chan == iface->conf->channel)
				continue; /* matching own primary channel */
			if (is_40_allowed(iface, chan))
				continue; /* not within affected channels */
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_DEBUG,
				       "20_40_INTOLERANT channel %d reported",
				       chan);
			is_ht40_allowed = 0;
		}

		data += 2 + ielen;
	}
	wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
		   is_ht40_allowed, iface->num_sta_ht40_intolerant);

	if (!is_ht40_allowed &&
	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
		if (iface->conf->secondary_channel) {
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_INFO,
				       "Switching to 20 MHz operation");
			iface->conf->secondary_channel = 0;
			ieee802_11_set_beacons(iface);
		}
		if (!iface->num_sta_ht40_intolerant &&
		    iface->conf->obss_interval) {
			unsigned int delay_time;
			delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
				iface->conf->obss_interval;
			eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
					     NULL);
			eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
					       hapd->iface, NULL);
			wpa_printf(MSG_DEBUG,
				   "Reschedule HT 20/40 timeout to occur in %u seconds",
				   delay_time);
		}
	}
}