xref: /freebsd/contrib/wpa/src/common/ieee802_11_common.c (revision 4b72b91a7132df1f77bbae194e1071ac621f1edb)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * IEEE 802.11 Common routines
34bc52338SCy Schubert  * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
125b9c547cSRui Paulo #include "defs.h"
13325151a3SRui Paulo #include "wpa_common.h"
1485732ac8SCy Schubert #include "drivers/driver.h"
15325151a3SRui Paulo #include "qca-vendor.h"
1639beb93cSSam Leffler #include "ieee802_11_defs.h"
1739beb93cSSam Leffler #include "ieee802_11_common.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler 
20e28a4053SRui Paulo static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
2139beb93cSSam Leffler 					    struct ieee802_11_elems *elems,
2239beb93cSSam Leffler 					    int show_errors)
2339beb93cSSam Leffler {
2439beb93cSSam Leffler 	unsigned int oui;
2539beb93cSSam Leffler 
2639beb93cSSam Leffler 	/* first 3 bytes in vendor specific information element are the IEEE
2739beb93cSSam Leffler 	 * OUI of the vendor. The following byte is used a vendor specific
2839beb93cSSam Leffler 	 * sub-type. */
2939beb93cSSam Leffler 	if (elen < 4) {
3039beb93cSSam Leffler 		if (show_errors) {
3139beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "short vendor specific "
3239beb93cSSam Leffler 				   "information element ignored (len=%lu)",
3339beb93cSSam Leffler 				   (unsigned long) elen);
3439beb93cSSam Leffler 		}
3539beb93cSSam Leffler 		return -1;
3639beb93cSSam Leffler 	}
3739beb93cSSam Leffler 
3839beb93cSSam Leffler 	oui = WPA_GET_BE24(pos);
3939beb93cSSam Leffler 	switch (oui) {
4039beb93cSSam Leffler 	case OUI_MICROSOFT:
4139beb93cSSam Leffler 		/* Microsoft/Wi-Fi information elements are further typed and
4239beb93cSSam Leffler 		 * subtyped */
4339beb93cSSam Leffler 		switch (pos[3]) {
4439beb93cSSam Leffler 		case 1:
4539beb93cSSam Leffler 			/* Microsoft OUI (00:50:F2) with OUI Type 1:
4639beb93cSSam Leffler 			 * real WPA information element */
4739beb93cSSam Leffler 			elems->wpa_ie = pos;
4839beb93cSSam Leffler 			elems->wpa_ie_len = elen;
4939beb93cSSam Leffler 			break;
503157ba21SRui Paulo 		case WMM_OUI_TYPE:
513157ba21SRui Paulo 			/* WMM information element */
5239beb93cSSam Leffler 			if (elen < 5) {
533157ba21SRui Paulo 				wpa_printf(MSG_MSGDUMP, "short WMM "
5439beb93cSSam Leffler 					   "information element ignored "
5539beb93cSSam Leffler 					   "(len=%lu)",
5639beb93cSSam Leffler 					   (unsigned long) elen);
5739beb93cSSam Leffler 				return -1;
5839beb93cSSam Leffler 			}
5939beb93cSSam Leffler 			switch (pos[4]) {
603157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
613157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
623157ba21SRui Paulo 				/*
633157ba21SRui Paulo 				 * Share same pointer since only one of these
643157ba21SRui Paulo 				 * is used and they start with same data.
653157ba21SRui Paulo 				 * Length field can be used to distinguish the
663157ba21SRui Paulo 				 * IEs.
673157ba21SRui Paulo 				 */
683157ba21SRui Paulo 				elems->wmm = pos;
693157ba21SRui Paulo 				elems->wmm_len = elen;
7039beb93cSSam Leffler 				break;
713157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
723157ba21SRui Paulo 				elems->wmm_tspec = pos;
733157ba21SRui Paulo 				elems->wmm_tspec_len = elen;
7439beb93cSSam Leffler 				break;
7539beb93cSSam Leffler 			default:
76f05cddf9SRui Paulo 				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
7739beb93cSSam Leffler 					   "information element ignored "
7839beb93cSSam Leffler 					   "(subtype=%d len=%lu)",
7939beb93cSSam Leffler 					   pos[4], (unsigned long) elen);
8039beb93cSSam Leffler 				return -1;
8139beb93cSSam Leffler 			}
8239beb93cSSam Leffler 			break;
8339beb93cSSam Leffler 		case 4:
8439beb93cSSam Leffler 			/* Wi-Fi Protected Setup (WPS) IE */
8539beb93cSSam Leffler 			elems->wps_ie = pos;
8639beb93cSSam Leffler 			elems->wps_ie_len = elen;
8739beb93cSSam Leffler 			break;
8839beb93cSSam Leffler 		default:
89f05cddf9SRui Paulo 			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
90f05cddf9SRui Paulo 				   "information element ignored "
91f05cddf9SRui Paulo 				   "(type=%d len=%lu)",
92f05cddf9SRui Paulo 				   pos[3], (unsigned long) elen);
93f05cddf9SRui Paulo 			return -1;
94f05cddf9SRui Paulo 		}
95f05cddf9SRui Paulo 		break;
96f05cddf9SRui Paulo 
97f05cddf9SRui Paulo 	case OUI_WFA:
98f05cddf9SRui Paulo 		switch (pos[3]) {
99f05cddf9SRui Paulo 		case P2P_OUI_TYPE:
100f05cddf9SRui Paulo 			/* Wi-Fi Alliance - P2P IE */
101f05cddf9SRui Paulo 			elems->p2p = pos;
102f05cddf9SRui Paulo 			elems->p2p_len = elen;
103f05cddf9SRui Paulo 			break;
104f05cddf9SRui Paulo 		case WFD_OUI_TYPE:
105f05cddf9SRui Paulo 			/* Wi-Fi Alliance - WFD IE */
106f05cddf9SRui Paulo 			elems->wfd = pos;
107f05cddf9SRui Paulo 			elems->wfd_len = elen;
108f05cddf9SRui Paulo 			break;
109f05cddf9SRui Paulo 		case HS20_INDICATION_OUI_TYPE:
110f05cddf9SRui Paulo 			/* Hotspot 2.0 */
111f05cddf9SRui Paulo 			elems->hs20 = pos;
112f05cddf9SRui Paulo 			elems->hs20_len = elen;
113f05cddf9SRui Paulo 			break;
1145b9c547cSRui Paulo 		case HS20_OSEN_OUI_TYPE:
1155b9c547cSRui Paulo 			/* Hotspot 2.0 OSEN */
1165b9c547cSRui Paulo 			elems->osen = pos;
1175b9c547cSRui Paulo 			elems->osen_len = elen;
1185b9c547cSRui Paulo 			break;
119780fb4a2SCy Schubert 		case MBO_OUI_TYPE:
120780fb4a2SCy Schubert 			/* MBO-OCE */
121780fb4a2SCy Schubert 			elems->mbo = pos;
122780fb4a2SCy Schubert 			elems->mbo_len = elen;
123780fb4a2SCy Schubert 			break;
12485732ac8SCy Schubert 		case HS20_ROAMING_CONS_SEL_OUI_TYPE:
12585732ac8SCy Schubert 			/* Hotspot 2.0 Roaming Consortium Selection */
12685732ac8SCy Schubert 			elems->roaming_cons_sel = pos;
12785732ac8SCy Schubert 			elems->roaming_cons_sel_len = elen;
12885732ac8SCy Schubert 			break;
1294bc52338SCy Schubert 		case MULTI_AP_OUI_TYPE:
1304bc52338SCy Schubert 			elems->multi_ap = pos;
1314bc52338SCy Schubert 			elems->multi_ap_len = elen;
1324bc52338SCy Schubert 			break;
133c1d255d3SCy Schubert 		case OWE_OUI_TYPE:
134c1d255d3SCy Schubert 			/* OWE Transition Mode element */
135c1d255d3SCy Schubert 			break;
136c1d255d3SCy Schubert 		case DPP_CC_OUI_TYPE:
137c1d255d3SCy Schubert 			/* DPP Configurator Connectivity element */
138c1d255d3SCy Schubert 			break;
139c1d255d3SCy Schubert 		case SAE_PK_OUI_TYPE:
140c1d255d3SCy Schubert 			elems->sae_pk = pos + 4;
141c1d255d3SCy Schubert 			elems->sae_pk_len = elen - 4;
142c1d255d3SCy Schubert 			break;
143f05cddf9SRui Paulo 		default:
144f05cddf9SRui Paulo 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
14539beb93cSSam Leffler 				   "information element ignored "
1465b9c547cSRui Paulo 				   "(type=%d len=%lu)",
14739beb93cSSam Leffler 				   pos[3], (unsigned long) elen);
14839beb93cSSam Leffler 			return -1;
14939beb93cSSam Leffler 		}
15039beb93cSSam Leffler 		break;
15139beb93cSSam Leffler 
15239beb93cSSam Leffler 	case OUI_BROADCOM:
15339beb93cSSam Leffler 		switch (pos[3]) {
15439beb93cSSam Leffler 		case VENDOR_HT_CAPAB_OUI_TYPE:
15539beb93cSSam Leffler 			elems->vendor_ht_cap = pos;
15639beb93cSSam Leffler 			elems->vendor_ht_cap_len = elen;
15739beb93cSSam Leffler 			break;
1585b9c547cSRui Paulo 		case VENDOR_VHT_TYPE:
1595b9c547cSRui Paulo 			if (elen > 4 &&
1605b9c547cSRui Paulo 			    (pos[4] == VENDOR_VHT_SUBTYPE ||
1615b9c547cSRui Paulo 			     pos[4] == VENDOR_VHT_SUBTYPE2)) {
1625b9c547cSRui Paulo 				elems->vendor_vht = pos;
1635b9c547cSRui Paulo 				elems->vendor_vht_len = elen;
1645b9c547cSRui Paulo 			} else
1655b9c547cSRui Paulo 				return -1;
1665b9c547cSRui Paulo 			break;
16739beb93cSSam Leffler 		default:
168f05cddf9SRui Paulo 			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
16939beb93cSSam Leffler 				   "information element ignored "
170f05cddf9SRui Paulo 				   "(type=%d len=%lu)",
17139beb93cSSam Leffler 				   pos[3], (unsigned long) elen);
17239beb93cSSam Leffler 			return -1;
17339beb93cSSam Leffler 		}
17439beb93cSSam Leffler 		break;
17539beb93cSSam Leffler 
176325151a3SRui Paulo 	case OUI_QCA:
177325151a3SRui Paulo 		switch (pos[3]) {
178325151a3SRui Paulo 		case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
179325151a3SRui Paulo 			elems->pref_freq_list = pos;
180325151a3SRui Paulo 			elems->pref_freq_list_len = elen;
181325151a3SRui Paulo 			break;
182325151a3SRui Paulo 		default:
183325151a3SRui Paulo 			wpa_printf(MSG_EXCESSIVE,
184325151a3SRui Paulo 				   "Unknown QCA information element ignored (type=%d len=%lu)",
185325151a3SRui Paulo 				   pos[3], (unsigned long) elen);
186325151a3SRui Paulo 			return -1;
187325151a3SRui Paulo 		}
188325151a3SRui Paulo 		break;
189325151a3SRui Paulo 
19039beb93cSSam Leffler 	default:
191f05cddf9SRui Paulo 		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
192f05cddf9SRui Paulo 			   "information element ignored (vendor OUI "
193f05cddf9SRui Paulo 			   "%02x:%02x:%02x len=%lu)",
19439beb93cSSam Leffler 			   pos[0], pos[1], pos[2], (unsigned long) elen);
19539beb93cSSam Leffler 		return -1;
19639beb93cSSam Leffler 	}
19739beb93cSSam Leffler 
19839beb93cSSam Leffler 	return 0;
19939beb93cSSam Leffler }
20039beb93cSSam Leffler 
20139beb93cSSam Leffler 
20285732ac8SCy Schubert static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
20385732ac8SCy Schubert 				      struct ieee802_11_elems *elems,
20485732ac8SCy Schubert 				      int show_errors)
20585732ac8SCy Schubert {
20685732ac8SCy Schubert 	u8 ext_id;
20785732ac8SCy Schubert 
20885732ac8SCy Schubert 	if (elen < 1) {
20985732ac8SCy Schubert 		if (show_errors) {
21085732ac8SCy Schubert 			wpa_printf(MSG_MSGDUMP,
21185732ac8SCy Schubert 				   "short information element (Ext)");
21285732ac8SCy Schubert 		}
21385732ac8SCy Schubert 		return -1;
21485732ac8SCy Schubert 	}
21585732ac8SCy Schubert 
21685732ac8SCy Schubert 	ext_id = *pos++;
21785732ac8SCy Schubert 	elen--;
21885732ac8SCy Schubert 
219c1d255d3SCy Schubert 	elems->frag_ies.last_eid_ext = 0;
220c1d255d3SCy Schubert 
22185732ac8SCy Schubert 	switch (ext_id) {
22285732ac8SCy Schubert 	case WLAN_EID_EXT_ASSOC_DELAY_INFO:
22385732ac8SCy Schubert 		if (elen != 1)
22485732ac8SCy Schubert 			break;
22585732ac8SCy Schubert 		elems->assoc_delay_info = pos;
22685732ac8SCy Schubert 		break;
22785732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_REQ_PARAMS:
22885732ac8SCy Schubert 		if (elen < 3)
22985732ac8SCy Schubert 			break;
23085732ac8SCy Schubert 		elems->fils_req_params = pos;
23185732ac8SCy Schubert 		elems->fils_req_params_len = elen;
23285732ac8SCy Schubert 		break;
23385732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_KEY_CONFIRM:
23485732ac8SCy Schubert 		elems->fils_key_confirm = pos;
23585732ac8SCy Schubert 		elems->fils_key_confirm_len = elen;
23685732ac8SCy Schubert 		break;
23785732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_SESSION:
23885732ac8SCy Schubert 		if (elen != FILS_SESSION_LEN)
23985732ac8SCy Schubert 			break;
24085732ac8SCy Schubert 		elems->fils_session = pos;
24185732ac8SCy Schubert 		break;
24285732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_HLP_CONTAINER:
24385732ac8SCy Schubert 		if (elen < 2 * ETH_ALEN)
24485732ac8SCy Schubert 			break;
24585732ac8SCy Schubert 		elems->fils_hlp = pos;
24685732ac8SCy Schubert 		elems->fils_hlp_len = elen;
24785732ac8SCy Schubert 		break;
24885732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
24985732ac8SCy Schubert 		if (elen < 1)
25085732ac8SCy Schubert 			break;
25185732ac8SCy Schubert 		elems->fils_ip_addr_assign = pos;
25285732ac8SCy Schubert 		elems->fils_ip_addr_assign_len = elen;
25385732ac8SCy Schubert 		break;
25485732ac8SCy Schubert 	case WLAN_EID_EXT_KEY_DELIVERY:
25585732ac8SCy Schubert 		if (elen < WPA_KEY_RSC_LEN)
25685732ac8SCy Schubert 			break;
25785732ac8SCy Schubert 		elems->key_delivery = pos;
25885732ac8SCy Schubert 		elems->key_delivery_len = elen;
25985732ac8SCy Schubert 		break;
260c1d255d3SCy Schubert 	case WLAN_EID_EXT_WRAPPED_DATA:
261c1d255d3SCy Schubert 		elems->wrapped_data = pos;
262c1d255d3SCy Schubert 		elems->wrapped_data_len = elen;
26385732ac8SCy Schubert 		break;
26485732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_PUBLIC_KEY:
26585732ac8SCy Schubert 		if (elen < 1)
26685732ac8SCy Schubert 			break;
26785732ac8SCy Schubert 		elems->fils_pk = pos;
26885732ac8SCy Schubert 		elems->fils_pk_len = elen;
26985732ac8SCy Schubert 		break;
27085732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_NONCE:
27185732ac8SCy Schubert 		if (elen != FILS_NONCE_LEN)
27285732ac8SCy Schubert 			break;
27385732ac8SCy Schubert 		elems->fils_nonce = pos;
27485732ac8SCy Schubert 		break;
27585732ac8SCy Schubert 	case WLAN_EID_EXT_OWE_DH_PARAM:
27685732ac8SCy Schubert 		if (elen < 2)
27785732ac8SCy Schubert 			break;
27885732ac8SCy Schubert 		elems->owe_dh = pos;
27985732ac8SCy Schubert 		elems->owe_dh_len = elen;
28085732ac8SCy Schubert 		break;
28185732ac8SCy Schubert 	case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
28285732ac8SCy Schubert 		elems->password_id = pos;
28385732ac8SCy Schubert 		elems->password_id_len = elen;
28485732ac8SCy Schubert 		break;
2854bc52338SCy Schubert 	case WLAN_EID_EXT_HE_CAPABILITIES:
2864bc52338SCy Schubert 		elems->he_capabilities = pos;
2874bc52338SCy Schubert 		elems->he_capabilities_len = elen;
2884bc52338SCy Schubert 		break;
289206b73d0SCy Schubert 	case WLAN_EID_EXT_HE_OPERATION:
290206b73d0SCy Schubert 		elems->he_operation = pos;
291206b73d0SCy Schubert 		elems->he_operation_len = elen;
292206b73d0SCy Schubert 		break;
2934bc52338SCy Schubert 	case WLAN_EID_EXT_OCV_OCI:
2944bc52338SCy Schubert 		elems->oci = pos;
2954bc52338SCy Schubert 		elems->oci_len = elen;
2964bc52338SCy Schubert 		break;
297c1d255d3SCy Schubert 	case WLAN_EID_EXT_SHORT_SSID_LIST:
298c1d255d3SCy Schubert 		elems->short_ssid_list = pos;
299c1d255d3SCy Schubert 		elems->short_ssid_list_len = elen;
300c1d255d3SCy Schubert 		break;
301c1d255d3SCy Schubert 	case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
302c1d255d3SCy Schubert 		if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
303c1d255d3SCy Schubert 			break;
304c1d255d3SCy Schubert 		elems->he_6ghz_band_cap = pos;
305c1d255d3SCy Schubert 		break;
306c1d255d3SCy Schubert 	case WLAN_EID_EXT_PASN_PARAMS:
307c1d255d3SCy Schubert 		elems->pasn_params = pos;
308c1d255d3SCy Schubert 		elems->pasn_params_len = elen;
309c1d255d3SCy Schubert 		break;
31085732ac8SCy Schubert 	default:
31185732ac8SCy Schubert 		if (show_errors) {
31285732ac8SCy Schubert 			wpa_printf(MSG_MSGDUMP,
31385732ac8SCy Schubert 				   "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
31485732ac8SCy Schubert 				   ext_id, (unsigned int) elen);
31585732ac8SCy Schubert 		}
31685732ac8SCy Schubert 		return -1;
31785732ac8SCy Schubert 	}
31885732ac8SCy Schubert 
319c1d255d3SCy Schubert 	if (elen == 254)
320c1d255d3SCy Schubert 		elems->frag_ies.last_eid_ext = ext_id;
321c1d255d3SCy Schubert 
32285732ac8SCy Schubert 	return 0;
32385732ac8SCy Schubert }
32485732ac8SCy Schubert 
32585732ac8SCy Schubert 
326c1d255d3SCy Schubert static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
327c1d255d3SCy Schubert 				      const u8 *pos, u8 elen)
328c1d255d3SCy Schubert {
329c1d255d3SCy Schubert 	if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
330c1d255d3SCy Schubert 		wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
331c1d255d3SCy Schubert 		return;
332c1d255d3SCy Schubert 	}
333c1d255d3SCy Schubert 
334c1d255d3SCy Schubert 	/*
335c1d255d3SCy Schubert 	 * Note: while EID == 0 is a valid ID (SSID IE), it should not be
336c1d255d3SCy Schubert 	 * fragmented.
337c1d255d3SCy Schubert 	 */
338c1d255d3SCy Schubert 	if (!frag_ies->last_eid) {
339c1d255d3SCy Schubert 		wpa_printf(MSG_MSGDUMP,
340c1d255d3SCy Schubert 			   "Fragment without a valid last element - skip");
341c1d255d3SCy Schubert 		return;
342c1d255d3SCy Schubert 	}
343c1d255d3SCy Schubert 
344c1d255d3SCy Schubert 	frag_ies->frags[frag_ies->n_frags].ie = pos;
345c1d255d3SCy Schubert 	frag_ies->frags[frag_ies->n_frags].ie_len = elen;
346c1d255d3SCy Schubert 	frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
347c1d255d3SCy Schubert 	frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
348c1d255d3SCy Schubert 	frag_ies->n_frags++;
349c1d255d3SCy Schubert }
350c1d255d3SCy Schubert 
351c1d255d3SCy Schubert 
35239beb93cSSam Leffler /**
35339beb93cSSam Leffler  * ieee802_11_parse_elems - Parse information elements in management frames
35439beb93cSSam Leffler  * @start: Pointer to the start of IEs
35539beb93cSSam Leffler  * @len: Length of IE buffer in octets
35639beb93cSSam Leffler  * @elems: Data structure for parsed elements
35739beb93cSSam Leffler  * @show_errors: Whether to show parsing errors in debug log
35839beb93cSSam Leffler  * Returns: Parsing result
35939beb93cSSam Leffler  */
360e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
36139beb93cSSam Leffler 				struct ieee802_11_elems *elems,
36239beb93cSSam Leffler 				int show_errors)
36339beb93cSSam Leffler {
3644bc52338SCy Schubert 	const struct element *elem;
36539beb93cSSam Leffler 	int unknown = 0;
36639beb93cSSam Leffler 
36739beb93cSSam Leffler 	os_memset(elems, 0, sizeof(*elems));
36839beb93cSSam Leffler 
3694bc52338SCy Schubert 	if (!start)
3704bc52338SCy Schubert 		return ParseOK;
37139beb93cSSam Leffler 
3724bc52338SCy Schubert 	for_each_element(elem, start, len) {
3734bc52338SCy Schubert 		u8 id = elem->id, elen = elem->datalen;
3744bc52338SCy Schubert 		const u8 *pos = elem->data;
37539beb93cSSam Leffler 
37639beb93cSSam Leffler 		switch (id) {
37739beb93cSSam Leffler 		case WLAN_EID_SSID:
378325151a3SRui Paulo 			if (elen > SSID_MAX_LEN) {
379325151a3SRui Paulo 				wpa_printf(MSG_DEBUG,
380325151a3SRui Paulo 					   "Ignored too long SSID element (elen=%u)",
381325151a3SRui Paulo 					   elen);
382325151a3SRui Paulo 				break;
383325151a3SRui Paulo 			}
384c1d255d3SCy Schubert 			if (elems->ssid) {
385c1d255d3SCy Schubert 				wpa_printf(MSG_MSGDUMP,
386c1d255d3SCy Schubert 					   "Ignored duplicated SSID element");
387c1d255d3SCy Schubert 				break;
388c1d255d3SCy Schubert 			}
38939beb93cSSam Leffler 			elems->ssid = pos;
39039beb93cSSam Leffler 			elems->ssid_len = elen;
39139beb93cSSam Leffler 			break;
39239beb93cSSam Leffler 		case WLAN_EID_SUPP_RATES:
39339beb93cSSam Leffler 			elems->supp_rates = pos;
39439beb93cSSam Leffler 			elems->supp_rates_len = elen;
39539beb93cSSam Leffler 			break;
39639beb93cSSam Leffler 		case WLAN_EID_DS_PARAMS:
397325151a3SRui Paulo 			if (elen < 1)
398325151a3SRui Paulo 				break;
39939beb93cSSam Leffler 			elems->ds_params = pos;
40039beb93cSSam Leffler 			break;
40139beb93cSSam Leffler 		case WLAN_EID_CF_PARAMS:
40239beb93cSSam Leffler 		case WLAN_EID_TIM:
40339beb93cSSam Leffler 			break;
40439beb93cSSam Leffler 		case WLAN_EID_CHALLENGE:
40539beb93cSSam Leffler 			elems->challenge = pos;
40639beb93cSSam Leffler 			elems->challenge_len = elen;
40739beb93cSSam Leffler 			break;
40839beb93cSSam Leffler 		case WLAN_EID_ERP_INFO:
409325151a3SRui Paulo 			if (elen < 1)
410325151a3SRui Paulo 				break;
41139beb93cSSam Leffler 			elems->erp_info = pos;
41239beb93cSSam Leffler 			break;
41339beb93cSSam Leffler 		case WLAN_EID_EXT_SUPP_RATES:
41439beb93cSSam Leffler 			elems->ext_supp_rates = pos;
41539beb93cSSam Leffler 			elems->ext_supp_rates_len = elen;
41639beb93cSSam Leffler 			break;
41739beb93cSSam Leffler 		case WLAN_EID_VENDOR_SPECIFIC:
41839beb93cSSam Leffler 			if (ieee802_11_parse_vendor_specific(pos, elen,
41939beb93cSSam Leffler 							     elems,
42039beb93cSSam Leffler 							     show_errors))
42139beb93cSSam Leffler 				unknown++;
42239beb93cSSam Leffler 			break;
42339beb93cSSam Leffler 		case WLAN_EID_RSN:
42439beb93cSSam Leffler 			elems->rsn_ie = pos;
42539beb93cSSam Leffler 			elems->rsn_ie_len = elen;
42639beb93cSSam Leffler 			break;
427c1d255d3SCy Schubert 		case WLAN_EID_RSNX:
428c1d255d3SCy Schubert 			elems->rsnxe = pos;
429c1d255d3SCy Schubert 			elems->rsnxe_len = elen;
430c1d255d3SCy Schubert 			break;
43139beb93cSSam Leffler 		case WLAN_EID_PWR_CAPABILITY:
43285732ac8SCy Schubert 			if (elen < 2)
43385732ac8SCy Schubert 				break;
43485732ac8SCy Schubert 			elems->power_capab = pos;
43585732ac8SCy Schubert 			elems->power_capab_len = elen;
43639beb93cSSam Leffler 			break;
43739beb93cSSam Leffler 		case WLAN_EID_SUPPORTED_CHANNELS:
43839beb93cSSam Leffler 			elems->supp_channels = pos;
43939beb93cSSam Leffler 			elems->supp_channels_len = elen;
44039beb93cSSam Leffler 			break;
44139beb93cSSam Leffler 		case WLAN_EID_MOBILITY_DOMAIN:
442325151a3SRui Paulo 			if (elen < sizeof(struct rsn_mdie))
443325151a3SRui Paulo 				break;
44439beb93cSSam Leffler 			elems->mdie = pos;
44539beb93cSSam Leffler 			elems->mdie_len = elen;
44639beb93cSSam Leffler 			break;
44739beb93cSSam Leffler 		case WLAN_EID_FAST_BSS_TRANSITION:
448325151a3SRui Paulo 			if (elen < sizeof(struct rsn_ftie))
449325151a3SRui Paulo 				break;
45039beb93cSSam Leffler 			elems->ftie = pos;
45139beb93cSSam Leffler 			elems->ftie_len = elen;
45239beb93cSSam Leffler 			break;
45339beb93cSSam Leffler 		case WLAN_EID_TIMEOUT_INTERVAL:
454325151a3SRui Paulo 			if (elen != 5)
455325151a3SRui Paulo 				break;
45639beb93cSSam Leffler 			elems->timeout_int = pos;
45739beb93cSSam Leffler 			break;
45839beb93cSSam Leffler 		case WLAN_EID_HT_CAP:
459325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_ht_capabilities))
460325151a3SRui Paulo 				break;
46139beb93cSSam Leffler 			elems->ht_capabilities = pos;
46239beb93cSSam Leffler 			break;
46339beb93cSSam Leffler 		case WLAN_EID_HT_OPERATION:
464325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_ht_operation))
465325151a3SRui Paulo 				break;
46639beb93cSSam Leffler 			elems->ht_operation = pos;
46739beb93cSSam Leffler 			break;
4685b9c547cSRui Paulo 		case WLAN_EID_MESH_CONFIG:
4695b9c547cSRui Paulo 			elems->mesh_config = pos;
4705b9c547cSRui Paulo 			elems->mesh_config_len = elen;
4715b9c547cSRui Paulo 			break;
4725b9c547cSRui Paulo 		case WLAN_EID_MESH_ID:
4735b9c547cSRui Paulo 			elems->mesh_id = pos;
4745b9c547cSRui Paulo 			elems->mesh_id_len = elen;
4755b9c547cSRui Paulo 			break;
4765b9c547cSRui Paulo 		case WLAN_EID_PEER_MGMT:
4775b9c547cSRui Paulo 			elems->peer_mgmt = pos;
4785b9c547cSRui Paulo 			elems->peer_mgmt_len = elen;
4795b9c547cSRui Paulo 			break;
480f05cddf9SRui Paulo 		case WLAN_EID_VHT_CAP:
481325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_vht_capabilities))
482325151a3SRui Paulo 				break;
483f05cddf9SRui Paulo 			elems->vht_capabilities = pos;
484f05cddf9SRui Paulo 			break;
485f05cddf9SRui Paulo 		case WLAN_EID_VHT_OPERATION:
486325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_vht_operation))
487325151a3SRui Paulo 				break;
488f05cddf9SRui Paulo 			elems->vht_operation = pos;
489f05cddf9SRui Paulo 			break;
4905b9c547cSRui Paulo 		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
4915b9c547cSRui Paulo 			if (elen != 1)
4925b9c547cSRui Paulo 				break;
4935b9c547cSRui Paulo 			elems->vht_opmode_notif = pos;
4945b9c547cSRui Paulo 			break;
495f05cddf9SRui Paulo 		case WLAN_EID_LINK_ID:
496f05cddf9SRui Paulo 			if (elen < 18)
497f05cddf9SRui Paulo 				break;
498f05cddf9SRui Paulo 			elems->link_id = pos;
499f05cddf9SRui Paulo 			break;
500f05cddf9SRui Paulo 		case WLAN_EID_INTERWORKING:
501f05cddf9SRui Paulo 			elems->interworking = pos;
502f05cddf9SRui Paulo 			elems->interworking_len = elen;
503f05cddf9SRui Paulo 			break;
5045b9c547cSRui Paulo 		case WLAN_EID_QOS_MAP_SET:
5055b9c547cSRui Paulo 			if (elen < 16)
5065b9c547cSRui Paulo 				break;
5075b9c547cSRui Paulo 			elems->qos_map_set = pos;
5085b9c547cSRui Paulo 			elems->qos_map_set_len = elen;
5095b9c547cSRui Paulo 			break;
510f05cddf9SRui Paulo 		case WLAN_EID_EXT_CAPAB:
511f05cddf9SRui Paulo 			elems->ext_capab = pos;
512f05cddf9SRui Paulo 			elems->ext_capab_len = elen;
513f05cddf9SRui Paulo 			break;
514f05cddf9SRui Paulo 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
515f05cddf9SRui Paulo 			if (elen < 3)
516f05cddf9SRui Paulo 				break;
517f05cddf9SRui Paulo 			elems->bss_max_idle_period = pos;
518f05cddf9SRui Paulo 			break;
519f05cddf9SRui Paulo 		case WLAN_EID_SSID_LIST:
520f05cddf9SRui Paulo 			elems->ssid_list = pos;
521f05cddf9SRui Paulo 			elems->ssid_list_len = elen;
522f05cddf9SRui Paulo 			break;
5235b9c547cSRui Paulo 		case WLAN_EID_AMPE:
5245b9c547cSRui Paulo 			elems->ampe = pos;
5255b9c547cSRui Paulo 			elems->ampe_len = elen;
5265b9c547cSRui Paulo 			break;
5275b9c547cSRui Paulo 		case WLAN_EID_MIC:
5285b9c547cSRui Paulo 			elems->mic = pos;
5295b9c547cSRui Paulo 			elems->mic_len = elen;
5305b9c547cSRui Paulo 			/* after mic everything is encrypted, so stop. */
5314bc52338SCy Schubert 			goto done;
532325151a3SRui Paulo 		case WLAN_EID_MULTI_BAND:
533325151a3SRui Paulo 			if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
534325151a3SRui Paulo 				wpa_printf(MSG_MSGDUMP,
535325151a3SRui Paulo 					   "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
536325151a3SRui Paulo 					   id, elen);
537325151a3SRui Paulo 				break;
538325151a3SRui Paulo 			}
539325151a3SRui Paulo 
540325151a3SRui Paulo 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
541325151a3SRui Paulo 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
542325151a3SRui Paulo 			elems->mb_ies.nof_ies++;
543325151a3SRui Paulo 			break;
544780fb4a2SCy Schubert 		case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
545780fb4a2SCy Schubert 			elems->supp_op_classes = pos;
546780fb4a2SCy Schubert 			elems->supp_op_classes_len = elen;
547780fb4a2SCy Schubert 			break;
548780fb4a2SCy Schubert 		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
549780fb4a2SCy Schubert 			elems->rrm_enabled = pos;
550780fb4a2SCy Schubert 			elems->rrm_enabled_len = elen;
551780fb4a2SCy Schubert 			break;
55285732ac8SCy Schubert 		case WLAN_EID_CAG_NUMBER:
55385732ac8SCy Schubert 			elems->cag_number = pos;
55485732ac8SCy Schubert 			elems->cag_number_len = elen;
55585732ac8SCy Schubert 			break;
55685732ac8SCy Schubert 		case WLAN_EID_AP_CSN:
55785732ac8SCy Schubert 			if (elen < 1)
55885732ac8SCy Schubert 				break;
55985732ac8SCy Schubert 			elems->ap_csn = pos;
56085732ac8SCy Schubert 			break;
56185732ac8SCy Schubert 		case WLAN_EID_FILS_INDICATION:
56285732ac8SCy Schubert 			if (elen < 2)
56385732ac8SCy Schubert 				break;
56485732ac8SCy Schubert 			elems->fils_indic = pos;
56585732ac8SCy Schubert 			elems->fils_indic_len = elen;
56685732ac8SCy Schubert 			break;
56785732ac8SCy Schubert 		case WLAN_EID_DILS:
56885732ac8SCy Schubert 			if (elen < 2)
56985732ac8SCy Schubert 				break;
57085732ac8SCy Schubert 			elems->dils = pos;
57185732ac8SCy Schubert 			elems->dils_len = elen;
57285732ac8SCy Schubert 			break;
573c1d255d3SCy Schubert 		case WLAN_EID_S1G_CAPABILITIES:
574c1d255d3SCy Schubert 			if (elen < 15)
575c1d255d3SCy Schubert 				break;
576c1d255d3SCy Schubert 			elems->s1g_capab = pos;
577c1d255d3SCy Schubert 			break;
57885732ac8SCy Schubert 		case WLAN_EID_FRAGMENT:
579c1d255d3SCy Schubert 			ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
58085732ac8SCy Schubert 			break;
58185732ac8SCy Schubert 		case WLAN_EID_EXTENSION:
58285732ac8SCy Schubert 			if (ieee802_11_parse_extension(pos, elen, elems,
58385732ac8SCy Schubert 						       show_errors))
58485732ac8SCy Schubert 				unknown++;
58585732ac8SCy Schubert 			break;
58639beb93cSSam Leffler 		default:
58739beb93cSSam Leffler 			unknown++;
58839beb93cSSam Leffler 			if (!show_errors)
58939beb93cSSam Leffler 				break;
59039beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
59139beb93cSSam Leffler 				   "ignored unknown element (id=%d elen=%d)",
59239beb93cSSam Leffler 				   id, elen);
59339beb93cSSam Leffler 			break;
59439beb93cSSam Leffler 		}
595c1d255d3SCy Schubert 
596c1d255d3SCy Schubert 		if (id != WLAN_EID_FRAGMENT && elen == 255)
597c1d255d3SCy Schubert 			elems->frag_ies.last_eid = id;
598c1d255d3SCy Schubert 
599c1d255d3SCy Schubert 		if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
600c1d255d3SCy Schubert 			elems->frag_ies.last_eid = 0;
60139beb93cSSam Leffler 	}
60239beb93cSSam Leffler 
6034bc52338SCy Schubert 	if (!for_each_element_completed(elem, start, len)) {
6044bc52338SCy Schubert 		if (show_errors) {
6054bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
6064bc52338SCy Schubert 				   "IEEE 802.11 element parse failed @%d",
6074bc52338SCy Schubert 				   (int) (start + len - (const u8 *) elem));
6084bc52338SCy Schubert 			wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
6094bc52338SCy Schubert 		}
61039beb93cSSam Leffler 		return ParseFailed;
6114bc52338SCy Schubert 	}
61239beb93cSSam Leffler 
6134bc52338SCy Schubert done:
61439beb93cSSam Leffler 	return unknown ? ParseUnknown : ParseOK;
61539beb93cSSam Leffler }
616e28a4053SRui Paulo 
617e28a4053SRui Paulo 
618e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
619e28a4053SRui Paulo {
6204bc52338SCy Schubert 	const struct element *elem;
621e28a4053SRui Paulo 	int count = 0;
622e28a4053SRui Paulo 
623e28a4053SRui Paulo 	if (ies == NULL)
624e28a4053SRui Paulo 		return 0;
625e28a4053SRui Paulo 
6264bc52338SCy Schubert 	for_each_element(elem, ies, ies_len)
627e28a4053SRui Paulo 		count++;
628e28a4053SRui Paulo 
629e28a4053SRui Paulo 	return count;
630e28a4053SRui Paulo }
631e28a4053SRui Paulo 
632e28a4053SRui Paulo 
633e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
634e28a4053SRui Paulo 					    u32 oui_type)
635e28a4053SRui Paulo {
636e28a4053SRui Paulo 	struct wpabuf *buf;
6374bc52338SCy Schubert 	const struct element *elem, *found = NULL;
638e28a4053SRui Paulo 
6394bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
6404bc52338SCy Schubert 		if (elem->datalen >= 4 &&
6414bc52338SCy Schubert 		    WPA_GET_BE32(elem->data) == oui_type) {
6424bc52338SCy Schubert 			found = elem;
643e28a4053SRui Paulo 			break;
644e28a4053SRui Paulo 		}
645e28a4053SRui Paulo 	}
646e28a4053SRui Paulo 
6474bc52338SCy Schubert 	if (!found)
648e28a4053SRui Paulo 		return NULL; /* No specified vendor IE found */
649e28a4053SRui Paulo 
650e28a4053SRui Paulo 	buf = wpabuf_alloc(ies_len);
651e28a4053SRui Paulo 	if (buf == NULL)
652e28a4053SRui Paulo 		return NULL;
653e28a4053SRui Paulo 
654e28a4053SRui Paulo 	/*
655e28a4053SRui Paulo 	 * There may be multiple vendor IEs in the message, so need to
656e28a4053SRui Paulo 	 * concatenate their data fields.
657e28a4053SRui Paulo 	 */
6584bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
6594bc52338SCy Schubert 		if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
6604bc52338SCy Schubert 			wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
661e28a4053SRui Paulo 	}
662e28a4053SRui Paulo 
663e28a4053SRui Paulo 	return buf;
664e28a4053SRui Paulo }
665f05cddf9SRui Paulo 
666f05cddf9SRui Paulo 
667f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
668f05cddf9SRui Paulo {
669f05cddf9SRui Paulo 	u16 fc, type, stype;
670f05cddf9SRui Paulo 
671f05cddf9SRui Paulo 	/*
672f05cddf9SRui Paulo 	 * PS-Poll frames are 16 bytes. All other frames are
673f05cddf9SRui Paulo 	 * 24 bytes or longer.
674f05cddf9SRui Paulo 	 */
675f05cddf9SRui Paulo 	if (len < 16)
676f05cddf9SRui Paulo 		return NULL;
677f05cddf9SRui Paulo 
678f05cddf9SRui Paulo 	fc = le_to_host16(hdr->frame_control);
679f05cddf9SRui Paulo 	type = WLAN_FC_GET_TYPE(fc);
680f05cddf9SRui Paulo 	stype = WLAN_FC_GET_STYPE(fc);
681f05cddf9SRui Paulo 
682f05cddf9SRui Paulo 	switch (type) {
683f05cddf9SRui Paulo 	case WLAN_FC_TYPE_DATA:
684f05cddf9SRui Paulo 		if (len < 24)
685f05cddf9SRui Paulo 			return NULL;
686f05cddf9SRui Paulo 		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
687f05cddf9SRui Paulo 		case WLAN_FC_FROMDS | WLAN_FC_TODS:
688f05cddf9SRui Paulo 		case WLAN_FC_TODS:
689f05cddf9SRui Paulo 			return hdr->addr1;
690f05cddf9SRui Paulo 		case WLAN_FC_FROMDS:
691f05cddf9SRui Paulo 			return hdr->addr2;
692f05cddf9SRui Paulo 		default:
693f05cddf9SRui Paulo 			return NULL;
694f05cddf9SRui Paulo 		}
695f05cddf9SRui Paulo 	case WLAN_FC_TYPE_CTRL:
696f05cddf9SRui Paulo 		if (stype != WLAN_FC_STYPE_PSPOLL)
697f05cddf9SRui Paulo 			return NULL;
698f05cddf9SRui Paulo 		return hdr->addr1;
699f05cddf9SRui Paulo 	case WLAN_FC_TYPE_MGMT:
700f05cddf9SRui Paulo 		return hdr->addr3;
701f05cddf9SRui Paulo 	default:
702f05cddf9SRui Paulo 		return NULL;
703f05cddf9SRui Paulo 	}
704f05cddf9SRui Paulo }
705f05cddf9SRui Paulo 
706f05cddf9SRui Paulo 
707f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
708f05cddf9SRui Paulo 			  const char *name, const char *val)
709f05cddf9SRui Paulo {
710f05cddf9SRui Paulo 	int num, v;
711f05cddf9SRui Paulo 	const char *pos;
712f05cddf9SRui Paulo 	struct hostapd_wmm_ac_params *ac;
713f05cddf9SRui Paulo 
714f05cddf9SRui Paulo 	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
715f05cddf9SRui Paulo 	pos = name + 7;
716f05cddf9SRui Paulo 	if (os_strncmp(pos, "be_", 3) == 0) {
717f05cddf9SRui Paulo 		num = 0;
718f05cddf9SRui Paulo 		pos += 3;
719f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "bk_", 3) == 0) {
720f05cddf9SRui Paulo 		num = 1;
721f05cddf9SRui Paulo 		pos += 3;
722f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "vi_", 3) == 0) {
723f05cddf9SRui Paulo 		num = 2;
724f05cddf9SRui Paulo 		pos += 3;
725f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "vo_", 3) == 0) {
726f05cddf9SRui Paulo 		num = 3;
727f05cddf9SRui Paulo 		pos += 3;
728f05cddf9SRui Paulo 	} else {
729f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
730f05cddf9SRui Paulo 		return -1;
731f05cddf9SRui Paulo 	}
732f05cddf9SRui Paulo 
733f05cddf9SRui Paulo 	ac = &wmm_ac_params[num];
734f05cddf9SRui Paulo 
735f05cddf9SRui Paulo 	if (os_strcmp(pos, "aifs") == 0) {
736f05cddf9SRui Paulo 		v = atoi(val);
737f05cddf9SRui Paulo 		if (v < 1 || v > 255) {
738f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
739f05cddf9SRui Paulo 			return -1;
740f05cddf9SRui Paulo 		}
741f05cddf9SRui Paulo 		ac->aifs = v;
742f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "cwmin") == 0) {
743f05cddf9SRui Paulo 		v = atoi(val);
744325151a3SRui Paulo 		if (v < 0 || v > 15) {
745f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
746f05cddf9SRui Paulo 			return -1;
747f05cddf9SRui Paulo 		}
748f05cddf9SRui Paulo 		ac->cwmin = v;
749f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "cwmax") == 0) {
750f05cddf9SRui Paulo 		v = atoi(val);
751325151a3SRui Paulo 		if (v < 0 || v > 15) {
752f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
753f05cddf9SRui Paulo 			return -1;
754f05cddf9SRui Paulo 		}
755f05cddf9SRui Paulo 		ac->cwmax = v;
756f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "txop_limit") == 0) {
757f05cddf9SRui Paulo 		v = atoi(val);
758f05cddf9SRui Paulo 		if (v < 0 || v > 0xffff) {
759f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
760f05cddf9SRui Paulo 			return -1;
761f05cddf9SRui Paulo 		}
762f05cddf9SRui Paulo 		ac->txop_limit = v;
763f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "acm") == 0) {
764f05cddf9SRui Paulo 		v = atoi(val);
765f05cddf9SRui Paulo 		if (v < 0 || v > 1) {
766f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
767f05cddf9SRui Paulo 			return -1;
768f05cddf9SRui Paulo 		}
769f05cddf9SRui Paulo 		ac->admission_control_mandatory = v;
770f05cddf9SRui Paulo 	} else {
771f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
772f05cddf9SRui Paulo 		return -1;
773f05cddf9SRui Paulo 	}
774f05cddf9SRui Paulo 
775f05cddf9SRui Paulo 	return 0;
776f05cddf9SRui Paulo }
7775b9c547cSRui Paulo 
7785b9c547cSRui Paulo 
779c1d255d3SCy Schubert /* convert floats with one decimal place to value*10 int, i.e.,
780c1d255d3SCy Schubert  * "1.5" will return 15
781c1d255d3SCy Schubert  */
782c1d255d3SCy Schubert static int hostapd_config_read_int10(const char *value)
783c1d255d3SCy Schubert {
784c1d255d3SCy Schubert 	int i, d;
785c1d255d3SCy Schubert 	char *pos;
786c1d255d3SCy Schubert 
787c1d255d3SCy Schubert 	i = atoi(value);
788c1d255d3SCy Schubert 	pos = os_strchr(value, '.');
789c1d255d3SCy Schubert 	d = 0;
790c1d255d3SCy Schubert 	if (pos) {
791c1d255d3SCy Schubert 		pos++;
792c1d255d3SCy Schubert 		if (*pos >= '0' && *pos <= '9')
793c1d255d3SCy Schubert 			d = *pos - '0';
794c1d255d3SCy Schubert 	}
795c1d255d3SCy Schubert 
796c1d255d3SCy Schubert 	return i * 10 + d;
797c1d255d3SCy Schubert }
798c1d255d3SCy Schubert 
799c1d255d3SCy Schubert 
800c1d255d3SCy Schubert static int valid_cw(int cw)
801c1d255d3SCy Schubert {
802c1d255d3SCy Schubert 	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
803c1d255d3SCy Schubert 		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
804c1d255d3SCy Schubert 		cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
805c1d255d3SCy Schubert 		cw == 32767);
806c1d255d3SCy Schubert }
807c1d255d3SCy Schubert 
808c1d255d3SCy Schubert 
809c1d255d3SCy Schubert int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
810c1d255d3SCy Schubert 			    const char *name, const char *val)
811c1d255d3SCy Schubert {
812c1d255d3SCy Schubert 	int num;
813c1d255d3SCy Schubert 	const char *pos;
814c1d255d3SCy Schubert 	struct hostapd_tx_queue_params *queue;
815c1d255d3SCy Schubert 
816c1d255d3SCy Schubert 	/* skip 'tx_queue_' prefix */
817c1d255d3SCy Schubert 	pos = name + 9;
818c1d255d3SCy Schubert 	if (os_strncmp(pos, "data", 4) == 0 &&
819c1d255d3SCy Schubert 	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
820c1d255d3SCy Schubert 		num = pos[4] - '0';
821c1d255d3SCy Schubert 		pos += 6;
822c1d255d3SCy Schubert 	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
823c1d255d3SCy Schubert 		   os_strncmp(pos, "beacon_", 7) == 0) {
824c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
825c1d255d3SCy Schubert 		return 0;
826c1d255d3SCy Schubert 	} else {
827c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
828c1d255d3SCy Schubert 		return -1;
829c1d255d3SCy Schubert 	}
830c1d255d3SCy Schubert 
831c1d255d3SCy Schubert 	if (num >= NUM_TX_QUEUES) {
832c1d255d3SCy Schubert 		/* for backwards compatibility, do not trigger failure */
833c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
834c1d255d3SCy Schubert 		return 0;
835c1d255d3SCy Schubert 	}
836c1d255d3SCy Schubert 
837c1d255d3SCy Schubert 	queue = &tx_queue[num];
838c1d255d3SCy Schubert 
839c1d255d3SCy Schubert 	if (os_strcmp(pos, "aifs") == 0) {
840c1d255d3SCy Schubert 		queue->aifs = atoi(val);
841c1d255d3SCy Schubert 		if (queue->aifs < 0 || queue->aifs > 255) {
842c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
843c1d255d3SCy Schubert 				   queue->aifs);
844c1d255d3SCy Schubert 			return -1;
845c1d255d3SCy Schubert 		}
846c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "cwmin") == 0) {
847c1d255d3SCy Schubert 		queue->cwmin = atoi(val);
848c1d255d3SCy Schubert 		if (!valid_cw(queue->cwmin)) {
849c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
850c1d255d3SCy Schubert 				   queue->cwmin);
851c1d255d3SCy Schubert 			return -1;
852c1d255d3SCy Schubert 		}
853c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "cwmax") == 0) {
854c1d255d3SCy Schubert 		queue->cwmax = atoi(val);
855c1d255d3SCy Schubert 		if (!valid_cw(queue->cwmax)) {
856c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
857c1d255d3SCy Schubert 				   queue->cwmax);
858c1d255d3SCy Schubert 			return -1;
859c1d255d3SCy Schubert 		}
860c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "burst") == 0) {
861c1d255d3SCy Schubert 		queue->burst = hostapd_config_read_int10(val);
862c1d255d3SCy Schubert 	} else {
863c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
864c1d255d3SCy Schubert 		return -1;
865c1d255d3SCy Schubert 	}
866c1d255d3SCy Schubert 
867c1d255d3SCy Schubert 	return 0;
868c1d255d3SCy Schubert }
869c1d255d3SCy Schubert 
870c1d255d3SCy Schubert 
8715b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
8725b9c547cSRui Paulo {
873325151a3SRui Paulo 	u8 op_class;
874325151a3SRui Paulo 
875206b73d0SCy Schubert 	return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
876780fb4a2SCy Schubert 					     &op_class, channel);
877325151a3SRui Paulo }
878325151a3SRui Paulo 
879325151a3SRui Paulo 
880325151a3SRui Paulo /**
881325151a3SRui Paulo  * ieee80211_freq_to_channel_ext - Convert frequency into channel info
882c1d255d3SCy Schubert  * for HT40, VHT, and HE. DFS channels are not covered.
883325151a3SRui Paulo  * @freq: Frequency (MHz) to convert
884325151a3SRui Paulo  * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
885c1d255d3SCy Schubert  * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
886325151a3SRui Paulo  * @op_class: Buffer for returning operating class
887325151a3SRui Paulo  * @channel: Buffer for returning channel number
888325151a3SRui Paulo  * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
889325151a3SRui Paulo  */
890325151a3SRui Paulo enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
891c1d255d3SCy Schubert 						   int sec_channel,
892c1d255d3SCy Schubert 						   int chanwidth,
893325151a3SRui Paulo 						   u8 *op_class, u8 *channel)
894325151a3SRui Paulo {
895780fb4a2SCy Schubert 	u8 vht_opclass;
896780fb4a2SCy Schubert 
897325151a3SRui Paulo 	/* TODO: more operating classes */
898325151a3SRui Paulo 
899325151a3SRui Paulo 	if (sec_channel > 1 || sec_channel < -1)
900325151a3SRui Paulo 		return NUM_HOSTAPD_MODES;
9015b9c547cSRui Paulo 
9025b9c547cSRui Paulo 	if (freq >= 2412 && freq <= 2472) {
903325151a3SRui Paulo 		if ((freq - 2407) % 5)
904325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
905325151a3SRui Paulo 
906c1d255d3SCy Schubert 		if (chanwidth)
907325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
908325151a3SRui Paulo 
909325151a3SRui Paulo 		/* 2.407 GHz, channels 1..13 */
910325151a3SRui Paulo 		if (sec_channel == 1)
911325151a3SRui Paulo 			*op_class = 83;
912325151a3SRui Paulo 		else if (sec_channel == -1)
913325151a3SRui Paulo 			*op_class = 84;
914325151a3SRui Paulo 		else
915325151a3SRui Paulo 			*op_class = 81;
916325151a3SRui Paulo 
9175b9c547cSRui Paulo 		*channel = (freq - 2407) / 5;
918325151a3SRui Paulo 
919325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211G;
920325151a3SRui Paulo 	}
921325151a3SRui Paulo 
922325151a3SRui Paulo 	if (freq == 2484) {
923c1d255d3SCy Schubert 		if (sec_channel || chanwidth)
924325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
925325151a3SRui Paulo 
926325151a3SRui Paulo 		*op_class = 82; /* channel 14 */
9275b9c547cSRui Paulo 		*channel = 14;
928325151a3SRui Paulo 
929325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211B;
930325151a3SRui Paulo 	}
931325151a3SRui Paulo 
932325151a3SRui Paulo 	if (freq >= 4900 && freq < 5000) {
933325151a3SRui Paulo 		if ((freq - 4000) % 5)
934325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
9355b9c547cSRui Paulo 		*channel = (freq - 4000) / 5;
936325151a3SRui Paulo 		*op_class = 0; /* TODO */
937325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
938325151a3SRui Paulo 	}
939325151a3SRui Paulo 
940c1d255d3SCy Schubert 	switch (chanwidth) {
941206b73d0SCy Schubert 	case CHANWIDTH_80MHZ:
942780fb4a2SCy Schubert 		vht_opclass = 128;
943780fb4a2SCy Schubert 		break;
944206b73d0SCy Schubert 	case CHANWIDTH_160MHZ:
945780fb4a2SCy Schubert 		vht_opclass = 129;
946780fb4a2SCy Schubert 		break;
947206b73d0SCy Schubert 	case CHANWIDTH_80P80MHZ:
948780fb4a2SCy Schubert 		vht_opclass = 130;
949780fb4a2SCy Schubert 		break;
950780fb4a2SCy Schubert 	default:
951780fb4a2SCy Schubert 		vht_opclass = 0;
952780fb4a2SCy Schubert 		break;
953780fb4a2SCy Schubert 	}
954780fb4a2SCy Schubert 
955325151a3SRui Paulo 	/* 5 GHz, channels 36..48 */
956325151a3SRui Paulo 	if (freq >= 5180 && freq <= 5240) {
957325151a3SRui Paulo 		if ((freq - 5000) % 5)
958325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
959325151a3SRui Paulo 
960780fb4a2SCy Schubert 		if (vht_opclass)
961780fb4a2SCy Schubert 			*op_class = vht_opclass;
962780fb4a2SCy Schubert 		else if (sec_channel == 1)
963325151a3SRui Paulo 			*op_class = 116;
964325151a3SRui Paulo 		else if (sec_channel == -1)
965325151a3SRui Paulo 			*op_class = 117;
966325151a3SRui Paulo 		else
967325151a3SRui Paulo 			*op_class = 115;
968325151a3SRui Paulo 
9695b9c547cSRui Paulo 		*channel = (freq - 5000) / 5;
970325151a3SRui Paulo 
971325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
972325151a3SRui Paulo 	}
973325151a3SRui Paulo 
97485732ac8SCy Schubert 	/* 5 GHz, channels 52..64 */
97585732ac8SCy Schubert 	if (freq >= 5260 && freq <= 5320) {
97685732ac8SCy Schubert 		if ((freq - 5000) % 5)
97785732ac8SCy Schubert 			return NUM_HOSTAPD_MODES;
97885732ac8SCy Schubert 
97985732ac8SCy Schubert 		if (vht_opclass)
98085732ac8SCy Schubert 			*op_class = vht_opclass;
98185732ac8SCy Schubert 		else if (sec_channel == 1)
98285732ac8SCy Schubert 			*op_class = 119;
98385732ac8SCy Schubert 		else if (sec_channel == -1)
98485732ac8SCy Schubert 			*op_class = 120;
98585732ac8SCy Schubert 		else
98685732ac8SCy Schubert 			*op_class = 118;
98785732ac8SCy Schubert 
98885732ac8SCy Schubert 		*channel = (freq - 5000) / 5;
98985732ac8SCy Schubert 
99085732ac8SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
99185732ac8SCy Schubert 	}
99285732ac8SCy Schubert 
993c1d255d3SCy Schubert 	/* 5 GHz, channels 149..177 */
994c1d255d3SCy Schubert 	if (freq >= 5745 && freq <= 5885) {
995325151a3SRui Paulo 		if ((freq - 5000) % 5)
996325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
997325151a3SRui Paulo 
998780fb4a2SCy Schubert 		if (vht_opclass)
999780fb4a2SCy Schubert 			*op_class = vht_opclass;
1000780fb4a2SCy Schubert 		else if (sec_channel == 1)
1001780fb4a2SCy Schubert 			*op_class = 126;
1002780fb4a2SCy Schubert 		else if (sec_channel == -1)
1003780fb4a2SCy Schubert 			*op_class = 127;
1004780fb4a2SCy Schubert 		else if (freq <= 5805)
1005780fb4a2SCy Schubert 			*op_class = 124;
1006780fb4a2SCy Schubert 		else
1007325151a3SRui Paulo 			*op_class = 125;
1008325151a3SRui Paulo 
1009325151a3SRui Paulo 		*channel = (freq - 5000) / 5;
1010325151a3SRui Paulo 
1011325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1012325151a3SRui Paulo 	}
1013325151a3SRui Paulo 
1014*4b72b91aSCy Schubert 	/* 5 GHz, channels 100..144 */
1015*4b72b91aSCy Schubert 	if (freq >= 5500 && freq <= 5720) {
1016780fb4a2SCy Schubert 		if ((freq - 5000) % 5)
1017780fb4a2SCy Schubert 			return NUM_HOSTAPD_MODES;
1018780fb4a2SCy Schubert 
1019780fb4a2SCy Schubert 		if (vht_opclass)
1020780fb4a2SCy Schubert 			*op_class = vht_opclass;
1021780fb4a2SCy Schubert 		else if (sec_channel == 1)
1022780fb4a2SCy Schubert 			*op_class = 122;
1023780fb4a2SCy Schubert 		else if (sec_channel == -1)
1024780fb4a2SCy Schubert 			*op_class = 123;
1025780fb4a2SCy Schubert 		else
1026780fb4a2SCy Schubert 			*op_class = 121;
1027780fb4a2SCy Schubert 
1028780fb4a2SCy Schubert 		*channel = (freq - 5000) / 5;
1029780fb4a2SCy Schubert 
1030780fb4a2SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1031780fb4a2SCy Schubert 	}
1032780fb4a2SCy Schubert 
1033325151a3SRui Paulo 	if (freq >= 5000 && freq < 5900) {
1034325151a3SRui Paulo 		if ((freq - 5000) % 5)
1035325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1036325151a3SRui Paulo 		*channel = (freq - 5000) / 5;
1037325151a3SRui Paulo 		*op_class = 0; /* TODO */
1038325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1039325151a3SRui Paulo 	}
1040325151a3SRui Paulo 
1041c1d255d3SCy Schubert 	if (freq > 5950 && freq <= 7115) {
1042c1d255d3SCy Schubert 		if ((freq - 5950) % 5)
1043325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1044325151a3SRui Paulo 
1045c1d255d3SCy Schubert 		switch (chanwidth) {
1046c1d255d3SCy Schubert 		case CHANWIDTH_80MHZ:
1047c1d255d3SCy Schubert 			*op_class = 133;
1048c1d255d3SCy Schubert 			break;
1049c1d255d3SCy Schubert 		case CHANWIDTH_160MHZ:
1050c1d255d3SCy Schubert 			*op_class = 134;
1051c1d255d3SCy Schubert 			break;
1052c1d255d3SCy Schubert 		case CHANWIDTH_80P80MHZ:
1053c1d255d3SCy Schubert 			*op_class = 135;
1054c1d255d3SCy Schubert 			break;
1055c1d255d3SCy Schubert 		default:
1056c1d255d3SCy Schubert 			if (sec_channel)
1057c1d255d3SCy Schubert 				*op_class = 132;
1058c1d255d3SCy Schubert 			else
1059c1d255d3SCy Schubert 				*op_class = 131;
1060c1d255d3SCy Schubert 			break;
1061c1d255d3SCy Schubert 		}
1062c1d255d3SCy Schubert 
1063c1d255d3SCy Schubert 		*channel = (freq - 5950) / 5;
1064c1d255d3SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1065c1d255d3SCy Schubert 	}
1066c1d255d3SCy Schubert 
1067c1d255d3SCy Schubert 	if (freq == 5935) {
1068c1d255d3SCy Schubert 		*op_class = 136;
1069c1d255d3SCy Schubert 		*channel = (freq - 5925) / 5;
1070c1d255d3SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1071c1d255d3SCy Schubert 	}
1072c1d255d3SCy Schubert 
1073c1d255d3SCy Schubert 	/* 56.16 GHz, channel 1..6 */
1074c1d255d3SCy Schubert 	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
1075c1d255d3SCy Schubert 		if (sec_channel)
1076c1d255d3SCy Schubert 			return NUM_HOSTAPD_MODES;
1077c1d255d3SCy Schubert 
1078c1d255d3SCy Schubert 		switch (chanwidth) {
1079c1d255d3SCy Schubert 		case CHANWIDTH_USE_HT:
1080c1d255d3SCy Schubert 		case CHANWIDTH_2160MHZ:
10815b9c547cSRui Paulo 			*channel = (freq - 56160) / 2160;
1082325151a3SRui Paulo 			*op_class = 180;
1083c1d255d3SCy Schubert 			break;
1084c1d255d3SCy Schubert 		case CHANWIDTH_4320MHZ:
1085c1d255d3SCy Schubert 			/* EDMG channels 9 - 13 */
1086c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 5)
1087c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1088c1d255d3SCy Schubert 
1089c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 8;
1090c1d255d3SCy Schubert 			*op_class = 181;
1091c1d255d3SCy Schubert 			break;
1092c1d255d3SCy Schubert 		case CHANWIDTH_6480MHZ:
1093c1d255d3SCy Schubert 			/* EDMG channels 17 - 20 */
1094c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 4)
1095c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1096c1d255d3SCy Schubert 
1097c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 16;
1098c1d255d3SCy Schubert 			*op_class = 182;
1099c1d255d3SCy Schubert 			break;
1100c1d255d3SCy Schubert 		case CHANWIDTH_8640MHZ:
1101c1d255d3SCy Schubert 			/* EDMG channels 25 - 27 */
1102c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 3)
1103c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1104c1d255d3SCy Schubert 
1105c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 24;
1106c1d255d3SCy Schubert 			*op_class = 183;
1107c1d255d3SCy Schubert 			break;
1108c1d255d3SCy Schubert 		default:
1109c1d255d3SCy Schubert 			return NUM_HOSTAPD_MODES;
1110c1d255d3SCy Schubert 		}
1111325151a3SRui Paulo 
1112325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211AD;
11135b9c547cSRui Paulo 	}
11145b9c547cSRui Paulo 
1115325151a3SRui Paulo 	return NUM_HOSTAPD_MODES;
11165b9c547cSRui Paulo }
11175b9c547cSRui Paulo 
11185b9c547cSRui Paulo 
11194bc52338SCy Schubert int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
11204bc52338SCy Schubert 				  int sec_channel, u8 *op_class, u8 *channel)
11214bc52338SCy Schubert {
1122c1d255d3SCy Schubert 	int cw = CHAN_WIDTH_UNKNOWN;
11234bc52338SCy Schubert 
11244bc52338SCy Schubert 	switch (chanwidth) {
11254bc52338SCy Schubert 	case CHAN_WIDTH_UNKNOWN:
11264bc52338SCy Schubert 	case CHAN_WIDTH_20_NOHT:
11274bc52338SCy Schubert 	case CHAN_WIDTH_20:
11284bc52338SCy Schubert 	case CHAN_WIDTH_40:
1129c1d255d3SCy Schubert 		cw = CHANWIDTH_USE_HT;
11304bc52338SCy Schubert 		break;
11314bc52338SCy Schubert 	case CHAN_WIDTH_80:
1132c1d255d3SCy Schubert 		cw = CHANWIDTH_80MHZ;
11334bc52338SCy Schubert 		break;
11344bc52338SCy Schubert 	case CHAN_WIDTH_80P80:
1135c1d255d3SCy Schubert 		cw = CHANWIDTH_80P80MHZ;
11364bc52338SCy Schubert 		break;
11374bc52338SCy Schubert 	case CHAN_WIDTH_160:
1138c1d255d3SCy Schubert 		cw = CHANWIDTH_160MHZ;
1139c1d255d3SCy Schubert 		break;
1140c1d255d3SCy Schubert 	case CHAN_WIDTH_2160:
1141c1d255d3SCy Schubert 		cw = CHANWIDTH_2160MHZ;
1142c1d255d3SCy Schubert 		break;
1143c1d255d3SCy Schubert 	case CHAN_WIDTH_4320:
1144c1d255d3SCy Schubert 		cw = CHANWIDTH_4320MHZ;
1145c1d255d3SCy Schubert 		break;
1146c1d255d3SCy Schubert 	case CHAN_WIDTH_6480:
1147c1d255d3SCy Schubert 		cw = CHANWIDTH_6480MHZ;
1148c1d255d3SCy Schubert 		break;
1149c1d255d3SCy Schubert 	case CHAN_WIDTH_8640:
1150c1d255d3SCy Schubert 		cw = CHANWIDTH_8640MHZ;
11514bc52338SCy Schubert 		break;
11524bc52338SCy Schubert 	}
11534bc52338SCy Schubert 
1154c1d255d3SCy Schubert 	if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
11554bc52338SCy Schubert 					  channel) == NUM_HOSTAPD_MODES) {
11564bc52338SCy Schubert 		wpa_printf(MSG_WARNING,
11574bc52338SCy Schubert 			   "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
11584bc52338SCy Schubert 			   freq, chanwidth, sec_channel);
11594bc52338SCy Schubert 		return -1;
11604bc52338SCy Schubert 	}
11614bc52338SCy Schubert 
11624bc52338SCy Schubert 	return 0;
11634bc52338SCy Schubert }
11644bc52338SCy Schubert 
11654bc52338SCy Schubert 
1166325151a3SRui Paulo static const char *const us_op_class_cc[] = {
11675b9c547cSRui Paulo 	"US", "CA", NULL
11685b9c547cSRui Paulo };
11695b9c547cSRui Paulo 
1170325151a3SRui Paulo static const char *const eu_op_class_cc[] = {
11715b9c547cSRui Paulo 	"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
11725b9c547cSRui Paulo 	"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
11735b9c547cSRui Paulo 	"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
11745b9c547cSRui Paulo 	"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
11755b9c547cSRui Paulo };
11765b9c547cSRui Paulo 
1177325151a3SRui Paulo static const char *const jp_op_class_cc[] = {
11785b9c547cSRui Paulo 	"JP", NULL
11795b9c547cSRui Paulo };
11805b9c547cSRui Paulo 
1181325151a3SRui Paulo static const char *const cn_op_class_cc[] = {
1182325151a3SRui Paulo 	"CN", NULL
11835b9c547cSRui Paulo };
11845b9c547cSRui Paulo 
11855b9c547cSRui Paulo 
1186325151a3SRui Paulo static int country_match(const char *const cc[], const char *const country)
11875b9c547cSRui Paulo {
11885b9c547cSRui Paulo 	int i;
11895b9c547cSRui Paulo 
11905b9c547cSRui Paulo 	if (country == NULL)
11915b9c547cSRui Paulo 		return 0;
11925b9c547cSRui Paulo 	for (i = 0; cc[i]; i++) {
11935b9c547cSRui Paulo 		if (cc[i][0] == country[0] && cc[i][1] == country[1])
11945b9c547cSRui Paulo 			return 1;
11955b9c547cSRui Paulo 	}
11965b9c547cSRui Paulo 
11975b9c547cSRui Paulo 	return 0;
11985b9c547cSRui Paulo }
11995b9c547cSRui Paulo 
12005b9c547cSRui Paulo 
12015b9c547cSRui Paulo static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
12025b9c547cSRui Paulo {
12035b9c547cSRui Paulo 	switch (op_class) {
12045b9c547cSRui Paulo 	case 12: /* channels 1..11 */
12055b9c547cSRui Paulo 	case 32: /* channels 1..7; 40 MHz */
12065b9c547cSRui Paulo 	case 33: /* channels 5..11; 40 MHz */
12075b9c547cSRui Paulo 		if (chan < 1 || chan > 11)
12085b9c547cSRui Paulo 			return -1;
12095b9c547cSRui Paulo 		return 2407 + 5 * chan;
12105b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
12115b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
12125b9c547cSRui Paulo 	case 22: /* channels 36,44; 40 MHz */
12135b9c547cSRui Paulo 	case 23: /* channels 52,60; 40 MHz */
12145b9c547cSRui Paulo 	case 27: /* channels 40,48; 40 MHz */
12155b9c547cSRui Paulo 	case 28: /* channels 56,64; 40 MHz */
12165b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
12175b9c547cSRui Paulo 			return -1;
12185b9c547cSRui Paulo 		return 5000 + 5 * chan;
12195b9c547cSRui Paulo 	case 4: /* channels 100-144 */
12205b9c547cSRui Paulo 	case 24: /* channels 100-140; 40 MHz */
12215b9c547cSRui Paulo 		if (chan < 100 || chan > 144)
12225b9c547cSRui Paulo 			return -1;
12235b9c547cSRui Paulo 		return 5000 + 5 * chan;
12245b9c547cSRui Paulo 	case 3: /* channels 149,153,157,161 */
12255b9c547cSRui Paulo 	case 25: /* channels 149,157; 40 MHz */
12265b9c547cSRui Paulo 	case 26: /* channels 149,157; 40 MHz */
12275b9c547cSRui Paulo 	case 30: /* channels 153,161; 40 MHz */
12285b9c547cSRui Paulo 	case 31: /* channels 153,161; 40 MHz */
12295b9c547cSRui Paulo 		if (chan < 149 || chan > 161)
12305b9c547cSRui Paulo 			return -1;
12315b9c547cSRui Paulo 		return 5000 + 5 * chan;
1232325151a3SRui Paulo 	case 5: /* channels 149,153,157,161,165 */
1233325151a3SRui Paulo 		if (chan < 149 || chan > 165)
1234325151a3SRui Paulo 			return -1;
1235325151a3SRui Paulo 		return 5000 + 5 * chan;
1236c1d255d3SCy Schubert 	case 34: /* 60 GHz band, channels 1..8 */
1237c1d255d3SCy Schubert 		if (chan < 1 || chan > 8)
12385b9c547cSRui Paulo 			return -1;
12395b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1240c1d255d3SCy Schubert 	case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
1241c1d255d3SCy Schubert 		if (chan < 9 || chan > 15)
1242c1d255d3SCy Schubert 			return -1;
1243c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1244c1d255d3SCy Schubert 	case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
1245c1d255d3SCy Schubert 		if (chan < 17 || chan > 22)
1246c1d255d3SCy Schubert 			return -1;
1247c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1248c1d255d3SCy Schubert 	case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
1249c1d255d3SCy Schubert 		if (chan < 25 || chan > 29)
1250c1d255d3SCy Schubert 			return -1;
1251c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
12525b9c547cSRui Paulo 	}
12535b9c547cSRui Paulo 	return -1;
12545b9c547cSRui Paulo }
12555b9c547cSRui Paulo 
12565b9c547cSRui Paulo 
12575b9c547cSRui Paulo static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
12585b9c547cSRui Paulo {
12595b9c547cSRui Paulo 	switch (op_class) {
12605b9c547cSRui Paulo 	case 4: /* channels 1..13 */
12615b9c547cSRui Paulo 	case 11: /* channels 1..9; 40 MHz */
12625b9c547cSRui Paulo 	case 12: /* channels 5..13; 40 MHz */
12635b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
12645b9c547cSRui Paulo 			return -1;
12655b9c547cSRui Paulo 		return 2407 + 5 * chan;
12665b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
12675b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
12685b9c547cSRui Paulo 	case 5: /* channels 36,44; 40 MHz */
12695b9c547cSRui Paulo 	case 6: /* channels 52,60; 40 MHz */
12705b9c547cSRui Paulo 	case 8: /* channels 40,48; 40 MHz */
12715b9c547cSRui Paulo 	case 9: /* channels 56,64; 40 MHz */
12725b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
12735b9c547cSRui Paulo 			return -1;
12745b9c547cSRui Paulo 		return 5000 + 5 * chan;
12755b9c547cSRui Paulo 	case 3: /* channels 100-140 */
12765b9c547cSRui Paulo 	case 7: /* channels 100-132; 40 MHz */
12775b9c547cSRui Paulo 	case 10: /* channels 104-136; 40 MHz */
12785b9c547cSRui Paulo 	case 16: /* channels 100-140 */
12795b9c547cSRui Paulo 		if (chan < 100 || chan > 140)
12805b9c547cSRui Paulo 			return -1;
12815b9c547cSRui Paulo 		return 5000 + 5 * chan;
12825b9c547cSRui Paulo 	case 17: /* channels 149,153,157,161,165,169 */
12835b9c547cSRui Paulo 		if (chan < 149 || chan > 169)
12845b9c547cSRui Paulo 			return -1;
12855b9c547cSRui Paulo 		return 5000 + 5 * chan;
1286c1d255d3SCy Schubert 	case 18: /* 60 GHz band, channels 1..6 */
1287c1d255d3SCy Schubert 		if (chan < 1 || chan > 6)
12885b9c547cSRui Paulo 			return -1;
12895b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1290c1d255d3SCy Schubert 	case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
1291c1d255d3SCy Schubert 		if (chan < 9 || chan > 11)
1292c1d255d3SCy Schubert 			return -1;
1293c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1294c1d255d3SCy Schubert 	case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
1295c1d255d3SCy Schubert 		if (chan < 17 || chan > 18)
1296c1d255d3SCy Schubert 			return -1;
1297c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1298c1d255d3SCy Schubert 	case 23: /* 60 GHz band, EDMG CB4, channels 25 */
1299c1d255d3SCy Schubert 		if (chan != 25)
1300c1d255d3SCy Schubert 			return -1;
1301c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
13025b9c547cSRui Paulo 	}
13035b9c547cSRui Paulo 	return -1;
13045b9c547cSRui Paulo }
13055b9c547cSRui Paulo 
13065b9c547cSRui Paulo 
13075b9c547cSRui Paulo static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
13085b9c547cSRui Paulo {
13095b9c547cSRui Paulo 	switch (op_class) {
13105b9c547cSRui Paulo 	case 30: /* channels 1..13 */
13115b9c547cSRui Paulo 	case 56: /* channels 1..9; 40 MHz */
13125b9c547cSRui Paulo 	case 57: /* channels 5..13; 40 MHz */
13135b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
13145b9c547cSRui Paulo 			return -1;
13155b9c547cSRui Paulo 		return 2407 + 5 * chan;
13165b9c547cSRui Paulo 	case 31: /* channel 14 */
13175b9c547cSRui Paulo 		if (chan != 14)
13185b9c547cSRui Paulo 			return -1;
13195b9c547cSRui Paulo 		return 2414 + 5 * chan;
13205b9c547cSRui Paulo 	case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
13215b9c547cSRui Paulo 	case 32: /* channels 52,56,60,64 */
13225b9c547cSRui Paulo 	case 33: /* channels 52,56,60,64 */
13235b9c547cSRui Paulo 	case 36: /* channels 36,44; 40 MHz */
13245b9c547cSRui Paulo 	case 37: /* channels 52,60; 40 MHz */
13255b9c547cSRui Paulo 	case 38: /* channels 52,60; 40 MHz */
13265b9c547cSRui Paulo 	case 41: /* channels 40,48; 40 MHz */
13275b9c547cSRui Paulo 	case 42: /* channels 56,64; 40 MHz */
13285b9c547cSRui Paulo 	case 43: /* channels 56,64; 40 MHz */
13295b9c547cSRui Paulo 		if (chan < 34 || chan > 64)
13305b9c547cSRui Paulo 			return -1;
13315b9c547cSRui Paulo 		return 5000 + 5 * chan;
13325b9c547cSRui Paulo 	case 34: /* channels 100-140 */
13335b9c547cSRui Paulo 	case 35: /* channels 100-140 */
13345b9c547cSRui Paulo 	case 39: /* channels 100-132; 40 MHz */
13355b9c547cSRui Paulo 	case 40: /* channels 100-132; 40 MHz */
13365b9c547cSRui Paulo 	case 44: /* channels 104-136; 40 MHz */
13375b9c547cSRui Paulo 	case 45: /* channels 104-136; 40 MHz */
13385b9c547cSRui Paulo 	case 58: /* channels 100-140 */
13395b9c547cSRui Paulo 		if (chan < 100 || chan > 140)
13405b9c547cSRui Paulo 			return -1;
13415b9c547cSRui Paulo 		return 5000 + 5 * chan;
1342c1d255d3SCy Schubert 	case 59: /* 60 GHz band, channels 1..6 */
1343c1d255d3SCy Schubert 		if (chan < 1 || chan > 6)
13445b9c547cSRui Paulo 			return -1;
13455b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1346c1d255d3SCy Schubert 	case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
1347c1d255d3SCy Schubert 		if (chan < 9 || chan > 11)
1348c1d255d3SCy Schubert 			return -1;
1349c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1350c1d255d3SCy Schubert 	case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
1351c1d255d3SCy Schubert 		if (chan < 17 || chan > 18)
1352c1d255d3SCy Schubert 			return -1;
1353c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1354c1d255d3SCy Schubert 	case 64: /* 60 GHz band, EDMG CB4, channel 25 */
1355c1d255d3SCy Schubert 		if (chan != 25)
1356c1d255d3SCy Schubert 			return -1;
1357c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
13585b9c547cSRui Paulo 	}
13595b9c547cSRui Paulo 	return -1;
13605b9c547cSRui Paulo }
13615b9c547cSRui Paulo 
13625b9c547cSRui Paulo 
13635b9c547cSRui Paulo static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
13645b9c547cSRui Paulo {
13655b9c547cSRui Paulo 	switch (op_class) {
13665b9c547cSRui Paulo 	case 7: /* channels 1..13 */
13675b9c547cSRui Paulo 	case 8: /* channels 1..9; 40 MHz */
13685b9c547cSRui Paulo 	case 9: /* channels 5..13; 40 MHz */
13695b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
13705b9c547cSRui Paulo 			return -1;
13715b9c547cSRui Paulo 		return 2407 + 5 * chan;
13725b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
13735b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
13745b9c547cSRui Paulo 	case 4: /* channels 36,44; 40 MHz */
13755b9c547cSRui Paulo 	case 5: /* channels 52,60; 40 MHz */
13765b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
13775b9c547cSRui Paulo 			return -1;
13785b9c547cSRui Paulo 		return 5000 + 5 * chan;
13795b9c547cSRui Paulo 	case 3: /* channels 149,153,157,161,165 */
13805b9c547cSRui Paulo 	case 6: /* channels 149,157; 40 MHz */
13815b9c547cSRui Paulo 		if (chan < 149 || chan > 165)
13825b9c547cSRui Paulo 			return -1;
13835b9c547cSRui Paulo 		return 5000 + 5 * chan;
13845b9c547cSRui Paulo 	}
13855b9c547cSRui Paulo 	return -1;
13865b9c547cSRui Paulo }
13875b9c547cSRui Paulo 
13885b9c547cSRui Paulo 
13895b9c547cSRui Paulo static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
13905b9c547cSRui Paulo {
13915b9c547cSRui Paulo 	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
13925b9c547cSRui Paulo 	switch (op_class) {
13935b9c547cSRui Paulo 	case 81:
13945b9c547cSRui Paulo 		/* channels 1..13 */
13955b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
13965b9c547cSRui Paulo 			return -1;
13975b9c547cSRui Paulo 		return 2407 + 5 * chan;
13985b9c547cSRui Paulo 	case 82:
13995b9c547cSRui Paulo 		/* channel 14 */
14005b9c547cSRui Paulo 		if (chan != 14)
14015b9c547cSRui Paulo 			return -1;
14025b9c547cSRui Paulo 		return 2414 + 5 * chan;
14035b9c547cSRui Paulo 	case 83: /* channels 1..9; 40 MHz */
14045b9c547cSRui Paulo 	case 84: /* channels 5..13; 40 MHz */
14055b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
14065b9c547cSRui Paulo 			return -1;
14075b9c547cSRui Paulo 		return 2407 + 5 * chan;
14085b9c547cSRui Paulo 	case 115: /* channels 36,40,44,48; indoor only */
14095b9c547cSRui Paulo 	case 116: /* channels 36,44; 40 MHz; indoor only */
14105b9c547cSRui Paulo 	case 117: /* channels 40,48; 40 MHz; indoor only */
14115b9c547cSRui Paulo 	case 118: /* channels 52,56,60,64; dfs */
14125b9c547cSRui Paulo 	case 119: /* channels 52,60; 40 MHz; dfs */
14135b9c547cSRui Paulo 	case 120: /* channels 56,64; 40 MHz; dfs */
14145b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
14155b9c547cSRui Paulo 			return -1;
14165b9c547cSRui Paulo 		return 5000 + 5 * chan;
14175b9c547cSRui Paulo 	case 121: /* channels 100-140 */
14185b9c547cSRui Paulo 	case 122: /* channels 100-142; 40 MHz */
14195b9c547cSRui Paulo 	case 123: /* channels 104-136; 40 MHz */
14205b9c547cSRui Paulo 		if (chan < 100 || chan > 140)
14215b9c547cSRui Paulo 			return -1;
14225b9c547cSRui Paulo 		return 5000 + 5 * chan;
14235b9c547cSRui Paulo 	case 124: /* channels 149,153,157,161 */
14245b9c547cSRui Paulo 		if (chan < 149 || chan > 161)
14255b9c547cSRui Paulo 			return -1;
14265b9c547cSRui Paulo 		return 5000 + 5 * chan;
1427c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,173,177 */
1428c1d255d3SCy Schubert 	case 126: /* channels 149,157,165,173; 40 MHz */
1429c1d255d3SCy Schubert 	case 127: /* channels 153,161,169,177; 40 MHz */
1430c1d255d3SCy Schubert 		if (chan < 149 || chan > 177)
1431325151a3SRui Paulo 			return -1;
1432325151a3SRui Paulo 		return 5000 + 5 * chan;
1433c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
1434c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
1435c1d255d3SCy Schubert 		if (chan < 36 || chan > 177)
14365b9c547cSRui Paulo 			return -1;
14375b9c547cSRui Paulo 		return 5000 + 5 * chan;
1438c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
1439c1d255d3SCy Schubert 		if (chan < 36 || chan > 177)
14405b9c547cSRui Paulo 			return -1;
14415b9c547cSRui Paulo 		return 5000 + 5 * chan;
1442c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
1443c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
1444c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
1445c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
1446c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
1447c1d255d3SCy Schubert 		if (chan < 1 || chan > 233)
1448c1d255d3SCy Schubert 			return -1;
1449c1d255d3SCy Schubert 		return 5950 + chan * 5;
1450c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
1451c1d255d3SCy Schubert 		if (chan == 2)
1452c1d255d3SCy Schubert 			return 5935;
1453c1d255d3SCy Schubert 		return -1;
1454c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
1455c1d255d3SCy Schubert 		if (chan < 1 || chan > 8)
14565b9c547cSRui Paulo 			return -1;
14575b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1458c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
1459c1d255d3SCy Schubert 		if (chan < 9 || chan > 15)
1460c1d255d3SCy Schubert 			return -1;
1461c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1462c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
1463c1d255d3SCy Schubert 		if (chan < 17 || chan > 22)
1464c1d255d3SCy Schubert 			return -1;
1465c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1466c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
1467c1d255d3SCy Schubert 		if (chan < 25 || chan > 29)
1468c1d255d3SCy Schubert 			return -1;
1469c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
14705b9c547cSRui Paulo 	}
14715b9c547cSRui Paulo 	return -1;
14725b9c547cSRui Paulo }
14735b9c547cSRui Paulo 
14745b9c547cSRui Paulo /**
14755b9c547cSRui Paulo  * ieee80211_chan_to_freq - Convert channel info to frequency
14765b9c547cSRui Paulo  * @country: Country code, if known; otherwise, global operating class is used
14775b9c547cSRui Paulo  * @op_class: Operating class
14785b9c547cSRui Paulo  * @chan: Channel number
14795b9c547cSRui Paulo  * Returns: Frequency in MHz or -1 if the specified channel is unknown
14805b9c547cSRui Paulo  */
14815b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
14825b9c547cSRui Paulo {
14835b9c547cSRui Paulo 	int freq;
14845b9c547cSRui Paulo 
14855b9c547cSRui Paulo 	if (country_match(us_op_class_cc, country)) {
14865b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_us(op_class, chan);
14875b9c547cSRui Paulo 		if (freq > 0)
14885b9c547cSRui Paulo 			return freq;
14895b9c547cSRui Paulo 	}
14905b9c547cSRui Paulo 
14915b9c547cSRui Paulo 	if (country_match(eu_op_class_cc, country)) {
14925b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_eu(op_class, chan);
14935b9c547cSRui Paulo 		if (freq > 0)
14945b9c547cSRui Paulo 			return freq;
14955b9c547cSRui Paulo 	}
14965b9c547cSRui Paulo 
14975b9c547cSRui Paulo 	if (country_match(jp_op_class_cc, country)) {
14985b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_jp(op_class, chan);
14995b9c547cSRui Paulo 		if (freq > 0)
15005b9c547cSRui Paulo 			return freq;
15015b9c547cSRui Paulo 	}
15025b9c547cSRui Paulo 
15035b9c547cSRui Paulo 	if (country_match(cn_op_class_cc, country)) {
15045b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_cn(op_class, chan);
15055b9c547cSRui Paulo 		if (freq > 0)
15065b9c547cSRui Paulo 			return freq;
15075b9c547cSRui Paulo 	}
15085b9c547cSRui Paulo 
15095b9c547cSRui Paulo 	return ieee80211_chan_to_freq_global(op_class, chan);
15105b9c547cSRui Paulo }
15115b9c547cSRui Paulo 
15125b9c547cSRui Paulo 
151385732ac8SCy Schubert int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
151485732ac8SCy Schubert 		     u16 num_modes)
15155b9c547cSRui Paulo {
151685732ac8SCy Schubert 	int i, j;
151785732ac8SCy Schubert 
151885732ac8SCy Schubert 	if (!modes || !num_modes)
151985732ac8SCy Schubert 		return (freq >= 5260 && freq <= 5320) ||
152085732ac8SCy Schubert 			(freq >= 5500 && freq <= 5700);
152185732ac8SCy Schubert 
152285732ac8SCy Schubert 	for (i = 0; i < num_modes; i++) {
152385732ac8SCy Schubert 		for (j = 0; j < modes[i].num_channels; j++) {
152485732ac8SCy Schubert 			if (modes[i].channels[j].freq == freq &&
152585732ac8SCy Schubert 			    (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
152685732ac8SCy Schubert 				return 1;
152785732ac8SCy Schubert 		}
152885732ac8SCy Schubert 	}
152985732ac8SCy Schubert 
153085732ac8SCy Schubert 	return 0;
15315b9c547cSRui Paulo }
15325b9c547cSRui Paulo 
15335b9c547cSRui Paulo 
1534*4b72b91aSCy Schubert /*
1535*4b72b91aSCy Schubert  * 802.11-2020: Table E-4 - Global operating classes
1536*4b72b91aSCy Schubert  * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123
1537*4b72b91aSCy Schubert  */
1538*4b72b91aSCy Schubert int is_dfs_global_op_class(u8 op_class)
1539*4b72b91aSCy Schubert {
1540*4b72b91aSCy Schubert     return (op_class >= 118) && (op_class <= 123);
1541*4b72b91aSCy Schubert }
1542*4b72b91aSCy Schubert 
1543*4b72b91aSCy Schubert 
15445b9c547cSRui Paulo static int is_11b(u8 rate)
15455b9c547cSRui Paulo {
15465b9c547cSRui Paulo 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
15475b9c547cSRui Paulo }
15485b9c547cSRui Paulo 
15495b9c547cSRui Paulo 
15505b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems)
15515b9c547cSRui Paulo {
15525b9c547cSRui Paulo 	int num_11b = 0, num_others = 0;
15535b9c547cSRui Paulo 	int i;
15545b9c547cSRui Paulo 
15555b9c547cSRui Paulo 	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
15565b9c547cSRui Paulo 		return 0;
15575b9c547cSRui Paulo 
15585b9c547cSRui Paulo 	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
15595b9c547cSRui Paulo 		if (is_11b(elems->supp_rates[i]))
15605b9c547cSRui Paulo 			num_11b++;
15615b9c547cSRui Paulo 		else
15625b9c547cSRui Paulo 			num_others++;
15635b9c547cSRui Paulo 	}
15645b9c547cSRui Paulo 
15655b9c547cSRui Paulo 	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
15665b9c547cSRui Paulo 	     i++) {
15675b9c547cSRui Paulo 		if (is_11b(elems->ext_supp_rates[i]))
15685b9c547cSRui Paulo 			num_11b++;
15695b9c547cSRui Paulo 		else
15705b9c547cSRui Paulo 			num_others++;
15715b9c547cSRui Paulo 	}
15725b9c547cSRui Paulo 
15735b9c547cSRui Paulo 	return num_11b > 0 && num_others == 0;
15745b9c547cSRui Paulo }
15755b9c547cSRui Paulo 
15765b9c547cSRui Paulo 
15775b9c547cSRui Paulo const char * fc2str(u16 fc)
15785b9c547cSRui Paulo {
15795b9c547cSRui Paulo 	u16 stype = WLAN_FC_GET_STYPE(fc);
15805b9c547cSRui Paulo #define C2S(x) case x: return #x;
15815b9c547cSRui Paulo 
15825b9c547cSRui Paulo 	switch (WLAN_FC_GET_TYPE(fc)) {
15835b9c547cSRui Paulo 	case WLAN_FC_TYPE_MGMT:
15845b9c547cSRui Paulo 		switch (stype) {
15855b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ASSOC_REQ)
15865b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ASSOC_RESP)
15875b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_REASSOC_REQ)
15885b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_REASSOC_RESP)
15895b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PROBE_REQ)
15905b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PROBE_RESP)
15915b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_BEACON)
15925b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ATIM)
15935b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DISASSOC)
15945b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_AUTH)
15955b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DEAUTH)
15965b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ACTION)
15975b9c547cSRui Paulo 		}
15985b9c547cSRui Paulo 		break;
15995b9c547cSRui Paulo 	case WLAN_FC_TYPE_CTRL:
16005b9c547cSRui Paulo 		switch (stype) {
16015b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PSPOLL)
16025b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_RTS)
16035b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CTS)
16045b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ACK)
16055b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFEND)
16065b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFENDACK)
16075b9c547cSRui Paulo 		}
16085b9c547cSRui Paulo 		break;
16095b9c547cSRui Paulo 	case WLAN_FC_TYPE_DATA:
16105b9c547cSRui Paulo 		switch (stype) {
16115b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA)
16125b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFACK)
16135b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFPOLL)
16145b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
16155b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_NULLFUNC)
16165b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFACK)
16175b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFPOLL)
16185b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFACKPOLL)
16195b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA)
16205b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
16215b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
16225b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
16235b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_NULL)
16245b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_CFPOLL)
16255b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
16265b9c547cSRui Paulo 		}
16275b9c547cSRui Paulo 		break;
16285b9c547cSRui Paulo 	}
16295b9c547cSRui Paulo 	return "WLAN_FC_TYPE_UNKNOWN";
16305b9c547cSRui Paulo #undef C2S
16315b9c547cSRui Paulo }
1632325151a3SRui Paulo 
1633325151a3SRui Paulo 
1634206b73d0SCy Schubert const char * reason2str(u16 reason)
1635206b73d0SCy Schubert {
1636206b73d0SCy Schubert #define R2S(r) case WLAN_REASON_ ## r: return #r;
1637206b73d0SCy Schubert 	switch (reason) {
1638206b73d0SCy Schubert 	R2S(UNSPECIFIED)
1639206b73d0SCy Schubert 	R2S(PREV_AUTH_NOT_VALID)
1640206b73d0SCy Schubert 	R2S(DEAUTH_LEAVING)
1641206b73d0SCy Schubert 	R2S(DISASSOC_DUE_TO_INACTIVITY)
1642206b73d0SCy Schubert 	R2S(DISASSOC_AP_BUSY)
1643206b73d0SCy Schubert 	R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
1644206b73d0SCy Schubert 	R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
1645206b73d0SCy Schubert 	R2S(DISASSOC_STA_HAS_LEFT)
1646206b73d0SCy Schubert 	R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
1647206b73d0SCy Schubert 	R2S(PWR_CAPABILITY_NOT_VALID)
1648206b73d0SCy Schubert 	R2S(SUPPORTED_CHANNEL_NOT_VALID)
1649206b73d0SCy Schubert 	R2S(BSS_TRANSITION_DISASSOC)
1650206b73d0SCy Schubert 	R2S(INVALID_IE)
1651206b73d0SCy Schubert 	R2S(MICHAEL_MIC_FAILURE)
1652206b73d0SCy Schubert 	R2S(4WAY_HANDSHAKE_TIMEOUT)
1653206b73d0SCy Schubert 	R2S(GROUP_KEY_UPDATE_TIMEOUT)
1654206b73d0SCy Schubert 	R2S(IE_IN_4WAY_DIFFERS)
1655206b73d0SCy Schubert 	R2S(GROUP_CIPHER_NOT_VALID)
1656206b73d0SCy Schubert 	R2S(PAIRWISE_CIPHER_NOT_VALID)
1657206b73d0SCy Schubert 	R2S(AKMP_NOT_VALID)
1658206b73d0SCy Schubert 	R2S(UNSUPPORTED_RSN_IE_VERSION)
1659206b73d0SCy Schubert 	R2S(INVALID_RSN_IE_CAPAB)
1660206b73d0SCy Schubert 	R2S(IEEE_802_1X_AUTH_FAILED)
1661206b73d0SCy Schubert 	R2S(CIPHER_SUITE_REJECTED)
1662206b73d0SCy Schubert 	R2S(TDLS_TEARDOWN_UNREACHABLE)
1663206b73d0SCy Schubert 	R2S(TDLS_TEARDOWN_UNSPECIFIED)
1664206b73d0SCy Schubert 	R2S(SSP_REQUESTED_DISASSOC)
1665206b73d0SCy Schubert 	R2S(NO_SSP_ROAMING_AGREEMENT)
1666206b73d0SCy Schubert 	R2S(BAD_CIPHER_OR_AKM)
1667206b73d0SCy Schubert 	R2S(NOT_AUTHORIZED_THIS_LOCATION)
1668206b73d0SCy Schubert 	R2S(SERVICE_CHANGE_PRECLUDES_TS)
1669206b73d0SCy Schubert 	R2S(UNSPECIFIED_QOS_REASON)
1670206b73d0SCy Schubert 	R2S(NOT_ENOUGH_BANDWIDTH)
1671206b73d0SCy Schubert 	R2S(DISASSOC_LOW_ACK)
1672206b73d0SCy Schubert 	R2S(EXCEEDED_TXOP)
1673206b73d0SCy Schubert 	R2S(STA_LEAVING)
1674206b73d0SCy Schubert 	R2S(END_TS_BA_DLS)
1675206b73d0SCy Schubert 	R2S(UNKNOWN_TS_BA)
1676206b73d0SCy Schubert 	R2S(TIMEOUT)
1677206b73d0SCy Schubert 	R2S(PEERKEY_MISMATCH)
1678206b73d0SCy Schubert 	R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
1679206b73d0SCy Schubert 	R2S(EXTERNAL_SERVICE_REQUIREMENTS)
1680206b73d0SCy Schubert 	R2S(INVALID_FT_ACTION_FRAME_COUNT)
1681206b73d0SCy Schubert 	R2S(INVALID_PMKID)
1682206b73d0SCy Schubert 	R2S(INVALID_MDE)
1683206b73d0SCy Schubert 	R2S(INVALID_FTE)
1684206b73d0SCy Schubert 	R2S(MESH_PEERING_CANCELLED)
1685206b73d0SCy Schubert 	R2S(MESH_MAX_PEERS)
1686206b73d0SCy Schubert 	R2S(MESH_CONFIG_POLICY_VIOLATION)
1687206b73d0SCy Schubert 	R2S(MESH_CLOSE_RCVD)
1688206b73d0SCy Schubert 	R2S(MESH_MAX_RETRIES)
1689206b73d0SCy Schubert 	R2S(MESH_CONFIRM_TIMEOUT)
1690206b73d0SCy Schubert 	R2S(MESH_INVALID_GTK)
1691206b73d0SCy Schubert 	R2S(MESH_INCONSISTENT_PARAMS)
1692206b73d0SCy Schubert 	R2S(MESH_INVALID_SECURITY_CAP)
1693206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
1694206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
1695206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
1696206b73d0SCy Schubert 	R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
1697206b73d0SCy Schubert 	R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
1698206b73d0SCy Schubert 	R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
1699206b73d0SCy Schubert 	}
1700206b73d0SCy Schubert 	return "UNKNOWN";
1701206b73d0SCy Schubert #undef R2S
1702206b73d0SCy Schubert }
1703206b73d0SCy Schubert 
1704206b73d0SCy Schubert 
1705206b73d0SCy Schubert const char * status2str(u16 status)
1706206b73d0SCy Schubert {
1707206b73d0SCy Schubert #define S2S(s) case WLAN_STATUS_ ## s: return #s;
1708206b73d0SCy Schubert 	switch (status) {
1709206b73d0SCy Schubert 	S2S(SUCCESS)
1710206b73d0SCy Schubert 	S2S(UNSPECIFIED_FAILURE)
1711206b73d0SCy Schubert 	S2S(TDLS_WAKEUP_ALTERNATE)
1712206b73d0SCy Schubert 	S2S(TDLS_WAKEUP_REJECT)
1713206b73d0SCy Schubert 	S2S(SECURITY_DISABLED)
1714206b73d0SCy Schubert 	S2S(UNACCEPTABLE_LIFETIME)
1715206b73d0SCy Schubert 	S2S(NOT_IN_SAME_BSS)
1716206b73d0SCy Schubert 	S2S(CAPS_UNSUPPORTED)
1717206b73d0SCy Schubert 	S2S(REASSOC_NO_ASSOC)
1718206b73d0SCy Schubert 	S2S(ASSOC_DENIED_UNSPEC)
1719206b73d0SCy Schubert 	S2S(NOT_SUPPORTED_AUTH_ALG)
1720206b73d0SCy Schubert 	S2S(UNKNOWN_AUTH_TRANSACTION)
1721206b73d0SCy Schubert 	S2S(CHALLENGE_FAIL)
1722206b73d0SCy Schubert 	S2S(AUTH_TIMEOUT)
1723206b73d0SCy Schubert 	S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
1724206b73d0SCy Schubert 	S2S(ASSOC_DENIED_RATES)
1725206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NOSHORT)
1726206b73d0SCy Schubert 	S2S(SPEC_MGMT_REQUIRED)
1727206b73d0SCy Schubert 	S2S(PWR_CAPABILITY_NOT_VALID)
1728206b73d0SCy Schubert 	S2S(SUPPORTED_CHANNEL_NOT_VALID)
1729206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
1730206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_HT)
1731206b73d0SCy Schubert 	S2S(R0KH_UNREACHABLE)
1732206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_PCO)
1733206b73d0SCy Schubert 	S2S(ASSOC_REJECTED_TEMPORARILY)
1734206b73d0SCy Schubert 	S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
1735206b73d0SCy Schubert 	S2S(UNSPECIFIED_QOS_FAILURE)
1736206b73d0SCy Schubert 	S2S(DENIED_INSUFFICIENT_BANDWIDTH)
1737206b73d0SCy Schubert 	S2S(DENIED_POOR_CHANNEL_CONDITIONS)
1738206b73d0SCy Schubert 	S2S(DENIED_QOS_NOT_SUPPORTED)
1739206b73d0SCy Schubert 	S2S(REQUEST_DECLINED)
1740206b73d0SCy Schubert 	S2S(INVALID_PARAMETERS)
1741206b73d0SCy Schubert 	S2S(REJECTED_WITH_SUGGESTED_CHANGES)
1742206b73d0SCy Schubert 	S2S(INVALID_IE)
1743206b73d0SCy Schubert 	S2S(GROUP_CIPHER_NOT_VALID)
1744206b73d0SCy Schubert 	S2S(PAIRWISE_CIPHER_NOT_VALID)
1745206b73d0SCy Schubert 	S2S(AKMP_NOT_VALID)
1746206b73d0SCy Schubert 	S2S(UNSUPPORTED_RSN_IE_VERSION)
1747206b73d0SCy Schubert 	S2S(INVALID_RSN_IE_CAPAB)
1748206b73d0SCy Schubert 	S2S(CIPHER_REJECTED_PER_POLICY)
1749206b73d0SCy Schubert 	S2S(TS_NOT_CREATED)
1750206b73d0SCy Schubert 	S2S(DIRECT_LINK_NOT_ALLOWED)
1751206b73d0SCy Schubert 	S2S(DEST_STA_NOT_PRESENT)
1752206b73d0SCy Schubert 	S2S(DEST_STA_NOT_QOS_STA)
1753206b73d0SCy Schubert 	S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
1754206b73d0SCy Schubert 	S2S(INVALID_FT_ACTION_FRAME_COUNT)
1755206b73d0SCy Schubert 	S2S(INVALID_PMKID)
1756206b73d0SCy Schubert 	S2S(INVALID_MDIE)
1757206b73d0SCy Schubert 	S2S(INVALID_FTIE)
1758206b73d0SCy Schubert 	S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
1759206b73d0SCy Schubert 	S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
1760206b73d0SCy Schubert 	S2S(TRY_ANOTHER_BSS)
1761206b73d0SCy Schubert 	S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
1762206b73d0SCy Schubert 	S2S(NO_OUTSTANDING_GAS_REQ)
1763206b73d0SCy Schubert 	S2S(GAS_RESP_NOT_RECEIVED)
1764206b73d0SCy Schubert 	S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
1765206b73d0SCy Schubert 	S2S(GAS_RESP_LARGER_THAN_LIMIT)
1766206b73d0SCy Schubert 	S2S(REQ_REFUSED_HOME)
1767206b73d0SCy Schubert 	S2S(ADV_SRV_UNREACHABLE)
1768206b73d0SCy Schubert 	S2S(REQ_REFUSED_SSPN)
1769206b73d0SCy Schubert 	S2S(REQ_REFUSED_UNAUTH_ACCESS)
1770206b73d0SCy Schubert 	S2S(INVALID_RSNIE)
1771206b73d0SCy Schubert 	S2S(U_APSD_COEX_NOT_SUPPORTED)
1772206b73d0SCy Schubert 	S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
1773206b73d0SCy Schubert 	S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
1774206b73d0SCy Schubert 	S2S(ANTI_CLOGGING_TOKEN_REQ)
1775206b73d0SCy Schubert 	S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
1776206b73d0SCy Schubert 	S2S(CANNOT_FIND_ALT_TBTT)
1777206b73d0SCy Schubert 	S2S(TRANSMISSION_FAILURE)
1778206b73d0SCy Schubert 	S2S(REQ_TCLAS_NOT_SUPPORTED)
1779206b73d0SCy Schubert 	S2S(TCLAS_RESOURCES_EXCHAUSTED)
1780206b73d0SCy Schubert 	S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
1781206b73d0SCy Schubert 	S2S(REJECT_WITH_SCHEDULE)
1782206b73d0SCy Schubert 	S2S(REJECT_NO_WAKEUP_SPECIFIED)
1783206b73d0SCy Schubert 	S2S(SUCCESS_POWER_SAVE_MODE)
1784206b73d0SCy Schubert 	S2S(PENDING_ADMITTING_FST_SESSION)
1785206b73d0SCy Schubert 	S2S(PERFORMING_FST_NOW)
1786206b73d0SCy Schubert 	S2S(PENDING_GAP_IN_BA_WINDOW)
1787206b73d0SCy Schubert 	S2S(REJECT_U_PID_SETTING)
1788206b73d0SCy Schubert 	S2S(REFUSED_EXTERNAL_REASON)
1789206b73d0SCy Schubert 	S2S(REFUSED_AP_OUT_OF_MEMORY)
1790206b73d0SCy Schubert 	S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
1791206b73d0SCy Schubert 	S2S(QUERY_RESP_OUTSTANDING)
1792206b73d0SCy Schubert 	S2S(REJECT_DSE_BAND)
1793206b73d0SCy Schubert 	S2S(TCLAS_PROCESSING_TERMINATED)
1794206b73d0SCy Schubert 	S2S(TS_SCHEDULE_CONFLICT)
1795206b73d0SCy Schubert 	S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
1796206b73d0SCy Schubert 	S2S(MCCAOP_RESERVATION_CONFLICT)
1797206b73d0SCy Schubert 	S2S(MAF_LIMIT_EXCEEDED)
1798206b73d0SCy Schubert 	S2S(MCCA_TRACK_LIMIT_EXCEEDED)
1799206b73d0SCy Schubert 	S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
1800206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_VHT)
1801206b73d0SCy Schubert 	S2S(ENABLEMENT_DENIED)
1802206b73d0SCy Schubert 	S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
1803206b73d0SCy Schubert 	S2S(AUTHORIZATION_DEENABLED)
1804206b73d0SCy Schubert 	S2S(FILS_AUTHENTICATION_FAILURE)
1805206b73d0SCy Schubert 	S2S(UNKNOWN_AUTHENTICATION_SERVER)
1806206b73d0SCy Schubert 	S2S(UNKNOWN_PASSWORD_IDENTIFIER)
1807c1d255d3SCy Schubert 	S2S(DENIED_HE_NOT_SUPPORTED)
1808c1d255d3SCy Schubert 	S2S(SAE_HASH_TO_ELEMENT)
1809c1d255d3SCy Schubert 	S2S(SAE_PK)
1810206b73d0SCy Schubert 	}
1811206b73d0SCy Schubert 	return "UNKNOWN";
1812206b73d0SCy Schubert #undef S2S
1813206b73d0SCy Schubert }
1814206b73d0SCy Schubert 
1815206b73d0SCy Schubert 
1816325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
1817325151a3SRui Paulo 		       size_t ies_len)
1818325151a3SRui Paulo {
18194bc52338SCy Schubert 	const struct element *elem;
18204bc52338SCy Schubert 
1821325151a3SRui Paulo 	os_memset(info, 0, sizeof(*info));
1822325151a3SRui Paulo 
18234bc52338SCy Schubert 	if (!ies_buf)
18244bc52338SCy Schubert 		return 0;
1825325151a3SRui Paulo 
18264bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
18274bc52338SCy Schubert 		if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
18284bc52338SCy Schubert 			return 0;
1829325151a3SRui Paulo 
18304bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
18314bc52338SCy Schubert 			   elem->datalen + 2);
18324bc52338SCy Schubert 		info->ies[info->nof_ies].ie = elem->data;
18334bc52338SCy Schubert 		info->ies[info->nof_ies].ie_len = elem->datalen;
1834325151a3SRui Paulo 		info->nof_ies++;
1835325151a3SRui Paulo 	}
1836325151a3SRui Paulo 
18374bc52338SCy Schubert 	if (!for_each_element_completed(elem, ies_buf, ies_len)) {
18384bc52338SCy Schubert 		wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
18394bc52338SCy Schubert 		return -1;
1840325151a3SRui Paulo 	}
1841325151a3SRui Paulo 
1842325151a3SRui Paulo 	return 0;
1843325151a3SRui Paulo }
1844325151a3SRui Paulo 
1845325151a3SRui Paulo 
1846325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
1847325151a3SRui Paulo {
1848325151a3SRui Paulo 	struct wpabuf *mb_ies = NULL;
1849325151a3SRui Paulo 
1850325151a3SRui Paulo 	WPA_ASSERT(info != NULL);
1851325151a3SRui Paulo 
1852325151a3SRui Paulo 	if (info->nof_ies) {
1853325151a3SRui Paulo 		u8 i;
1854325151a3SRui Paulo 		size_t mb_ies_size = 0;
1855325151a3SRui Paulo 
1856325151a3SRui Paulo 		for (i = 0; i < info->nof_ies; i++)
1857325151a3SRui Paulo 			mb_ies_size += 2 + info->ies[i].ie_len;
1858325151a3SRui Paulo 
1859325151a3SRui Paulo 		mb_ies = wpabuf_alloc(mb_ies_size);
1860325151a3SRui Paulo 		if (mb_ies) {
1861325151a3SRui Paulo 			for (i = 0; i < info->nof_ies; i++) {
1862325151a3SRui Paulo 				wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
1863325151a3SRui Paulo 				wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
1864325151a3SRui Paulo 				wpabuf_put_data(mb_ies,
1865325151a3SRui Paulo 						info->ies[i].ie,
1866325151a3SRui Paulo 						info->ies[i].ie_len);
1867325151a3SRui Paulo 			}
1868325151a3SRui Paulo 		}
1869325151a3SRui Paulo 	}
1870325151a3SRui Paulo 
1871325151a3SRui Paulo 	return mb_ies;
1872325151a3SRui Paulo }
1873780fb4a2SCy Schubert 
1874780fb4a2SCy Schubert 
1875780fb4a2SCy Schubert const struct oper_class_map global_op_class[] = {
1876780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
1877780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
1878780fb4a2SCy Schubert 
1879780fb4a2SCy Schubert 	/* Do not enable HT40 on 2.4 GHz for P2P use for now */
1880780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
1881780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
1882780fb4a2SCy Schubert 
1883780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
1884780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
1885780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
1886780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
1887780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
1888780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
1889780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
1890780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
1891780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
1892780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
1893c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
1894c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
1895c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
1896780fb4a2SCy Schubert 
1897780fb4a2SCy Schubert 	/*
1898c1d255d3SCy Schubert 	 * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center
1899c1d255d3SCy Schubert 	 * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing
1900c1d255d3SCy Schubert 	 * of 80 MHz, but currently use the following definition for simplicity
1901780fb4a2SCy Schubert 	 * (these center frequencies are not actual channels, which makes
1902c1d255d3SCy Schubert 	 * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take
1903780fb4a2SCy Schubert 	 * care of removing invalid channels.
1904780fb4a2SCy Schubert 	 */
1905c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
1906c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
1907c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
1908*4b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP },
1909*4b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP },
1910*4b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP },
1911c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
1912c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
1913c1d255d3SCy Schubert 
1914c1d255d3SCy Schubert 	/*
1915c1d255d3SCy Schubert 	 * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
1916c1d255d3SCy Schubert 	 * Class 180 has the legacy channels 1-6. Classes 181-183 include
1917c1d255d3SCy Schubert 	 * channels which implement channel bonding features.
1918c1d255d3SCy Schubert 	 */
1919c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP },
1920c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
1921c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
1922c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
1923c1d255d3SCy Schubert 
1924c1d255d3SCy Schubert 	/* Keep the operating class 130 as the last entry as a workaround for
1925c1d255d3SCy Schubert 	 * the OneHundredAndThirty Delimiter value used in the Supported
1926c1d255d3SCy Schubert 	 * Operating Classes element to indicate the end of the Operating
1927c1d255d3SCy Schubert 	 * Classes field. */
1928c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
1929780fb4a2SCy Schubert 	{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
1930780fb4a2SCy Schubert };
1931780fb4a2SCy Schubert 
1932780fb4a2SCy Schubert 
1933780fb4a2SCy Schubert static enum phy_type ieee80211_phy_type_by_freq(int freq)
1934780fb4a2SCy Schubert {
1935780fb4a2SCy Schubert 	enum hostapd_hw_mode hw_mode;
1936780fb4a2SCy Schubert 	u8 channel;
1937780fb4a2SCy Schubert 
1938780fb4a2SCy Schubert 	hw_mode = ieee80211_freq_to_chan(freq, &channel);
1939780fb4a2SCy Schubert 
1940780fb4a2SCy Schubert 	switch (hw_mode) {
1941780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211A:
1942780fb4a2SCy Schubert 		return PHY_TYPE_OFDM;
1943780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211B:
1944780fb4a2SCy Schubert 		return PHY_TYPE_HRDSSS;
1945780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211G:
1946780fb4a2SCy Schubert 		return PHY_TYPE_ERP;
1947780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211AD:
1948780fb4a2SCy Schubert 		return PHY_TYPE_DMG;
1949780fb4a2SCy Schubert 	default:
1950780fb4a2SCy Schubert 		return PHY_TYPE_UNSPECIFIED;
1951780fb4a2SCy Schubert 	};
1952780fb4a2SCy Schubert }
1953780fb4a2SCy Schubert 
1954780fb4a2SCy Schubert 
1955780fb4a2SCy Schubert /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
1956780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
1957780fb4a2SCy Schubert {
1958780fb4a2SCy Schubert 	if (vht)
1959780fb4a2SCy Schubert 		return PHY_TYPE_VHT;
1960780fb4a2SCy Schubert 	if (ht)
1961780fb4a2SCy Schubert 		return PHY_TYPE_HT;
1962780fb4a2SCy Schubert 
1963780fb4a2SCy Schubert 	return ieee80211_phy_type_by_freq(freq);
1964780fb4a2SCy Schubert }
1965780fb4a2SCy Schubert 
1966780fb4a2SCy Schubert 
1967780fb4a2SCy Schubert size_t global_op_class_size = ARRAY_SIZE(global_op_class);
1968780fb4a2SCy Schubert 
1969780fb4a2SCy Schubert 
1970780fb4a2SCy Schubert /**
1971780fb4a2SCy Schubert  * get_ie - Fetch a specified information element from IEs buffer
1972780fb4a2SCy Schubert  * @ies: Information elements buffer
1973780fb4a2SCy Schubert  * @len: Information elements buffer length
1974780fb4a2SCy Schubert  * @eid: Information element identifier (WLAN_EID_*)
1975780fb4a2SCy Schubert  * Returns: Pointer to the information element (id field) or %NULL if not found
1976780fb4a2SCy Schubert  *
1977780fb4a2SCy Schubert  * This function returns the first matching information element in the IEs
1978780fb4a2SCy Schubert  * buffer or %NULL in case the element is not found.
1979780fb4a2SCy Schubert  */
1980780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
1981780fb4a2SCy Schubert {
19824bc52338SCy Schubert 	const struct element *elem;
1983780fb4a2SCy Schubert 
1984780fb4a2SCy Schubert 	if (!ies)
1985780fb4a2SCy Schubert 		return NULL;
1986780fb4a2SCy Schubert 
19874bc52338SCy Schubert 	for_each_element_id(elem, eid, ies, len)
19884bc52338SCy Schubert 		return &elem->id;
1989780fb4a2SCy Schubert 
1990780fb4a2SCy Schubert 	return NULL;
1991780fb4a2SCy Schubert }
1992780fb4a2SCy Schubert 
1993780fb4a2SCy Schubert 
199485732ac8SCy Schubert /**
199585732ac8SCy Schubert  * get_ie_ext - Fetch a specified extended information element from IEs buffer
199685732ac8SCy Schubert  * @ies: Information elements buffer
199785732ac8SCy Schubert  * @len: Information elements buffer length
199885732ac8SCy Schubert  * @ext: Information element extension identifier (WLAN_EID_EXT_*)
199985732ac8SCy Schubert  * Returns: Pointer to the information element (id field) or %NULL if not found
200085732ac8SCy Schubert  *
200185732ac8SCy Schubert  * This function returns the first matching information element in the IEs
200285732ac8SCy Schubert  * buffer or %NULL in case the element is not found.
200385732ac8SCy Schubert  */
200485732ac8SCy Schubert const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
200585732ac8SCy Schubert {
20064bc52338SCy Schubert 	const struct element *elem;
200785732ac8SCy Schubert 
200885732ac8SCy Schubert 	if (!ies)
200985732ac8SCy Schubert 		return NULL;
201085732ac8SCy Schubert 
20114bc52338SCy Schubert 	for_each_element_extid(elem, ext, ies, len)
20124bc52338SCy Schubert 		return &elem->id;
201385732ac8SCy Schubert 
20144bc52338SCy Schubert 	return NULL;
20154bc52338SCy Schubert }
201685732ac8SCy Schubert 
201785732ac8SCy Schubert 
20184bc52338SCy Schubert const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
20194bc52338SCy Schubert {
20204bc52338SCy Schubert 	const struct element *elem;
20214bc52338SCy Schubert 
20224bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
20234bc52338SCy Schubert 		if (elem->datalen >= 4 &&
20244bc52338SCy Schubert 		    vendor_type == WPA_GET_BE32(elem->data))
20254bc52338SCy Schubert 			return &elem->id;
202685732ac8SCy Schubert 	}
202785732ac8SCy Schubert 
202885732ac8SCy Schubert 	return NULL;
202985732ac8SCy Schubert }
203085732ac8SCy Schubert 
203185732ac8SCy Schubert 
2032780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
2033780fb4a2SCy Schubert {
2034780fb4a2SCy Schubert 	/*
2035780fb4a2SCy Schubert 	 * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
2036780fb4a2SCy Schubert 	 * OUI (3), OUI type (1).
2037780fb4a2SCy Schubert 	 */
2038780fb4a2SCy Schubert 	if (len < 6 + attr_len) {
2039780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
2040780fb4a2SCy Schubert 			   "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
2041780fb4a2SCy Schubert 			   len, attr_len);
2042780fb4a2SCy Schubert 		return 0;
2043780fb4a2SCy Schubert 	}
2044780fb4a2SCy Schubert 
2045780fb4a2SCy Schubert 	*buf++ = WLAN_EID_VENDOR_SPECIFIC;
2046780fb4a2SCy Schubert 	*buf++ = attr_len + 4;
2047780fb4a2SCy Schubert 	WPA_PUT_BE24(buf, OUI_WFA);
2048780fb4a2SCy Schubert 	buf += 3;
2049780fb4a2SCy Schubert 	*buf++ = MBO_OUI_TYPE;
2050780fb4a2SCy Schubert 	os_memcpy(buf, attr, attr_len);
2051780fb4a2SCy Schubert 
2052780fb4a2SCy Schubert 	return 6 + attr_len;
2053780fb4a2SCy Schubert }
205485732ac8SCy Schubert 
205585732ac8SCy Schubert 
20564bc52338SCy Schubert size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value)
20574bc52338SCy Schubert {
20584bc52338SCy Schubert 	u8 *pos = buf;
20594bc52338SCy Schubert 
20604bc52338SCy Schubert 	if (len < 9)
20614bc52338SCy Schubert 		return 0;
20624bc52338SCy Schubert 
20634bc52338SCy Schubert 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
20644bc52338SCy Schubert 	*pos++ = 7; /* len */
20654bc52338SCy Schubert 	WPA_PUT_BE24(pos, OUI_WFA);
20664bc52338SCy Schubert 	pos += 3;
20674bc52338SCy Schubert 	*pos++ = MULTI_AP_OUI_TYPE;
20684bc52338SCy Schubert 	*pos++ = MULTI_AP_SUB_ELEM_TYPE;
20694bc52338SCy Schubert 	*pos++ = 1; /* len */
20704bc52338SCy Schubert 	*pos++ = value;
20714bc52338SCy Schubert 
20724bc52338SCy Schubert 	return pos - buf;
20734bc52338SCy Schubert }
20744bc52338SCy Schubert 
20754bc52338SCy Schubert 
207685732ac8SCy Schubert static const struct country_op_class us_op_class[] = {
207785732ac8SCy Schubert 	{ 1, 115 },
207885732ac8SCy Schubert 	{ 2, 118 },
207985732ac8SCy Schubert 	{ 3, 124 },
208085732ac8SCy Schubert 	{ 4, 121 },
208185732ac8SCy Schubert 	{ 5, 125 },
208285732ac8SCy Schubert 	{ 12, 81 },
208385732ac8SCy Schubert 	{ 22, 116 },
208485732ac8SCy Schubert 	{ 23, 119 },
208585732ac8SCy Schubert 	{ 24, 122 },
208685732ac8SCy Schubert 	{ 25, 126 },
208785732ac8SCy Schubert 	{ 26, 126 },
208885732ac8SCy Schubert 	{ 27, 117 },
208985732ac8SCy Schubert 	{ 28, 120 },
209085732ac8SCy Schubert 	{ 29, 123 },
209185732ac8SCy Schubert 	{ 30, 127 },
209285732ac8SCy Schubert 	{ 31, 127 },
209385732ac8SCy Schubert 	{ 32, 83 },
209485732ac8SCy Schubert 	{ 33, 84 },
209585732ac8SCy Schubert 	{ 34, 180 },
209685732ac8SCy Schubert };
209785732ac8SCy Schubert 
209885732ac8SCy Schubert static const struct country_op_class eu_op_class[] = {
209985732ac8SCy Schubert 	{ 1, 115 },
210085732ac8SCy Schubert 	{ 2, 118 },
210185732ac8SCy Schubert 	{ 3, 121 },
210285732ac8SCy Schubert 	{ 4, 81 },
210385732ac8SCy Schubert 	{ 5, 116 },
210485732ac8SCy Schubert 	{ 6, 119 },
210585732ac8SCy Schubert 	{ 7, 122 },
210685732ac8SCy Schubert 	{ 8, 117 },
210785732ac8SCy Schubert 	{ 9, 120 },
210885732ac8SCy Schubert 	{ 10, 123 },
210985732ac8SCy Schubert 	{ 11, 83 },
211085732ac8SCy Schubert 	{ 12, 84 },
211185732ac8SCy Schubert 	{ 17, 125 },
211285732ac8SCy Schubert 	{ 18, 180 },
211385732ac8SCy Schubert };
211485732ac8SCy Schubert 
211585732ac8SCy Schubert static const struct country_op_class jp_op_class[] = {
211685732ac8SCy Schubert 	{ 1, 115 },
211785732ac8SCy Schubert 	{ 30, 81 },
211885732ac8SCy Schubert 	{ 31, 82 },
211985732ac8SCy Schubert 	{ 32, 118 },
212085732ac8SCy Schubert 	{ 33, 118 },
212185732ac8SCy Schubert 	{ 34, 121 },
212285732ac8SCy Schubert 	{ 35, 121 },
212385732ac8SCy Schubert 	{ 36, 116 },
212485732ac8SCy Schubert 	{ 37, 119 },
212585732ac8SCy Schubert 	{ 38, 119 },
212685732ac8SCy Schubert 	{ 39, 122 },
212785732ac8SCy Schubert 	{ 40, 122 },
212885732ac8SCy Schubert 	{ 41, 117 },
212985732ac8SCy Schubert 	{ 42, 120 },
213085732ac8SCy Schubert 	{ 43, 120 },
213185732ac8SCy Schubert 	{ 44, 123 },
213285732ac8SCy Schubert 	{ 45, 123 },
213385732ac8SCy Schubert 	{ 56, 83 },
213485732ac8SCy Schubert 	{ 57, 84 },
213585732ac8SCy Schubert 	{ 58, 121 },
213685732ac8SCy Schubert 	{ 59, 180 },
213785732ac8SCy Schubert };
213885732ac8SCy Schubert 
213985732ac8SCy Schubert static const struct country_op_class cn_op_class[] = {
214085732ac8SCy Schubert 	{ 1, 115 },
214185732ac8SCy Schubert 	{ 2, 118 },
214285732ac8SCy Schubert 	{ 3, 125 },
214385732ac8SCy Schubert 	{ 4, 116 },
214485732ac8SCy Schubert 	{ 5, 119 },
214585732ac8SCy Schubert 	{ 6, 126 },
214685732ac8SCy Schubert 	{ 7, 81 },
214785732ac8SCy Schubert 	{ 8, 83 },
214885732ac8SCy Schubert 	{ 9, 84 },
214985732ac8SCy Schubert };
215085732ac8SCy Schubert 
215185732ac8SCy Schubert static u8
215285732ac8SCy Schubert global_op_class_from_country_array(u8 op_class, size_t array_size,
215385732ac8SCy Schubert 				   const struct country_op_class *country_array)
215485732ac8SCy Schubert {
215585732ac8SCy Schubert 	size_t i;
215685732ac8SCy Schubert 
215785732ac8SCy Schubert 	for (i = 0; i < array_size; i++) {
215885732ac8SCy Schubert 		if (country_array[i].country_op_class == op_class)
215985732ac8SCy Schubert 			return country_array[i].global_op_class;
216085732ac8SCy Schubert 	}
216185732ac8SCy Schubert 
216285732ac8SCy Schubert 	return 0;
216385732ac8SCy Schubert }
216485732ac8SCy Schubert 
216585732ac8SCy Schubert 
216685732ac8SCy Schubert u8 country_to_global_op_class(const char *country, u8 op_class)
216785732ac8SCy Schubert {
216885732ac8SCy Schubert 	const struct country_op_class *country_array;
216985732ac8SCy Schubert 	size_t size;
217085732ac8SCy Schubert 	u8 g_op_class;
217185732ac8SCy Schubert 
217285732ac8SCy Schubert 	if (country_match(us_op_class_cc, country)) {
217385732ac8SCy Schubert 		country_array = us_op_class;
217485732ac8SCy Schubert 		size = ARRAY_SIZE(us_op_class);
217585732ac8SCy Schubert 	} else if (country_match(eu_op_class_cc, country)) {
217685732ac8SCy Schubert 		country_array = eu_op_class;
217785732ac8SCy Schubert 		size = ARRAY_SIZE(eu_op_class);
217885732ac8SCy Schubert 	} else if (country_match(jp_op_class_cc, country)) {
217985732ac8SCy Schubert 		country_array = jp_op_class;
218085732ac8SCy Schubert 		size = ARRAY_SIZE(jp_op_class);
218185732ac8SCy Schubert 	} else if (country_match(cn_op_class_cc, country)) {
218285732ac8SCy Schubert 		country_array = cn_op_class;
218385732ac8SCy Schubert 		size = ARRAY_SIZE(cn_op_class);
218485732ac8SCy Schubert 	} else {
218585732ac8SCy Schubert 		/*
218685732ac8SCy Schubert 		 * Countries that do not match any of the above countries use
218785732ac8SCy Schubert 		 * global operating classes
218885732ac8SCy Schubert 		 */
218985732ac8SCy Schubert 		return op_class;
219085732ac8SCy Schubert 	}
219185732ac8SCy Schubert 
219285732ac8SCy Schubert 	g_op_class = global_op_class_from_country_array(op_class, size,
219385732ac8SCy Schubert 							country_array);
219485732ac8SCy Schubert 
219585732ac8SCy Schubert 	/*
219685732ac8SCy Schubert 	 * If the given operating class did not match any of the country's
219785732ac8SCy Schubert 	 * operating classes, assume that global operating class is used.
219885732ac8SCy Schubert 	 */
219985732ac8SCy Schubert 	return g_op_class ? g_op_class : op_class;
220085732ac8SCy Schubert }
220185732ac8SCy Schubert 
220285732ac8SCy Schubert 
220385732ac8SCy Schubert const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
220485732ac8SCy Schubert {
220585732ac8SCy Schubert 	const struct oper_class_map *op;
220685732ac8SCy Schubert 
220785732ac8SCy Schubert 	if (country)
220885732ac8SCy Schubert 		op_class = country_to_global_op_class(country, op_class);
220985732ac8SCy Schubert 
221085732ac8SCy Schubert 	op = &global_op_class[0];
221185732ac8SCy Schubert 	while (op->op_class && op->op_class != op_class)
221285732ac8SCy Schubert 		op++;
221385732ac8SCy Schubert 
221485732ac8SCy Schubert 	if (!op->op_class)
221585732ac8SCy Schubert 		return NULL;
221685732ac8SCy Schubert 
221785732ac8SCy Schubert 	return op;
221885732ac8SCy Schubert }
221985732ac8SCy Schubert 
222085732ac8SCy Schubert 
22214bc52338SCy Schubert int oper_class_bw_to_int(const struct oper_class_map *map)
22224bc52338SCy Schubert {
22234bc52338SCy Schubert 	switch (map->bw) {
22244bc52338SCy Schubert 	case BW20:
22254bc52338SCy Schubert 		return 20;
2226c1d255d3SCy Schubert 	case BW40:
22274bc52338SCy Schubert 	case BW40PLUS:
22284bc52338SCy Schubert 	case BW40MINUS:
22294bc52338SCy Schubert 		return 40;
22304bc52338SCy Schubert 	case BW80:
22314bc52338SCy Schubert 		return 80;
22324bc52338SCy Schubert 	case BW80P80:
22334bc52338SCy Schubert 	case BW160:
22344bc52338SCy Schubert 		return 160;
22354bc52338SCy Schubert 	case BW2160:
22364bc52338SCy Schubert 		return 2160;
22374bc52338SCy Schubert 	default:
22384bc52338SCy Schubert 		return 0;
22394bc52338SCy Schubert 	}
22404bc52338SCy Schubert }
22414bc52338SCy Schubert 
22424bc52338SCy Schubert 
2243c1d255d3SCy Schubert int center_idx_to_bw_6ghz(u8 idx)
2244c1d255d3SCy Schubert {
2245c1d255d3SCy Schubert 	/* Channel: 2 */
2246c1d255d3SCy Schubert 	if (idx == 2)
2247c1d255d3SCy Schubert 		return 0; /* 20 MHz */
2248c1d255d3SCy Schubert 	/* channels: 1, 5, 9, 13... */
2249c1d255d3SCy Schubert 	if ((idx & 0x3) == 0x1)
2250c1d255d3SCy Schubert 		return 0; /* 20 MHz */
2251c1d255d3SCy Schubert 	/* channels 3, 11, 19... */
2252c1d255d3SCy Schubert 	if ((idx & 0x7) == 0x3)
2253c1d255d3SCy Schubert 		return 1; /* 40 MHz */
2254c1d255d3SCy Schubert 	/* channels 7, 23, 39.. */
2255c1d255d3SCy Schubert 	if ((idx & 0xf) == 0x7)
2256c1d255d3SCy Schubert 		return 2; /* 80 MHz */
2257c1d255d3SCy Schubert 	/* channels 15, 47, 79...*/
2258c1d255d3SCy Schubert 	if ((idx & 0x1f) == 0xf)
2259c1d255d3SCy Schubert 		return 3; /* 160 MHz */
2260c1d255d3SCy Schubert 
2261c1d255d3SCy Schubert 	return -1;
2262c1d255d3SCy Schubert }
2263c1d255d3SCy Schubert 
2264c1d255d3SCy Schubert 
2265c1d255d3SCy Schubert bool is_6ghz_freq(int freq)
2266c1d255d3SCy Schubert {
2267c1d255d3SCy Schubert 	if (freq < 5935 || freq > 7115)
2268c1d255d3SCy Schubert 		return false;
2269c1d255d3SCy Schubert 
2270c1d255d3SCy Schubert 	if (freq == 5935)
2271c1d255d3SCy Schubert 		return true;
2272c1d255d3SCy Schubert 
2273c1d255d3SCy Schubert 	if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
2274c1d255d3SCy Schubert 		return false;
2275c1d255d3SCy Schubert 
2276c1d255d3SCy Schubert 	return true;
2277c1d255d3SCy Schubert }
2278c1d255d3SCy Schubert 
2279c1d255d3SCy Schubert 
2280c1d255d3SCy Schubert bool is_6ghz_op_class(u8 op_class)
2281c1d255d3SCy Schubert {
2282c1d255d3SCy Schubert 	return op_class >= 131 && op_class <= 136;
2283c1d255d3SCy Schubert }
2284c1d255d3SCy Schubert 
2285c1d255d3SCy Schubert 
2286c1d255d3SCy Schubert bool is_6ghz_psc_frequency(int freq)
2287c1d255d3SCy Schubert {
2288c1d255d3SCy Schubert 	int i;
2289c1d255d3SCy Schubert 
2290c1d255d3SCy Schubert 	if (!is_6ghz_freq(freq) || freq == 5935)
2291c1d255d3SCy Schubert 		return false;
2292c1d255d3SCy Schubert 	if ((((freq - 5950) / 5) & 0x3) != 0x1)
2293c1d255d3SCy Schubert 		return false;
2294c1d255d3SCy Schubert 
2295c1d255d3SCy Schubert 	i = (freq - 5950 + 55) % 80;
2296c1d255d3SCy Schubert 	if (i == 0)
2297c1d255d3SCy Schubert 		i = (freq - 5950 + 55) / 80;
2298c1d255d3SCy Schubert 
2299c1d255d3SCy Schubert 	if (i >= 1 && i <= 15)
2300c1d255d3SCy Schubert 		return true;
2301c1d255d3SCy Schubert 
2302c1d255d3SCy Schubert 	return false;
2303c1d255d3SCy Schubert }
2304c1d255d3SCy Schubert 
2305c1d255d3SCy Schubert 
2306*4b72b91aSCy Schubert /**
2307*4b72b91aSCy Schubert  * get_6ghz_sec_channel - Get the relative position of the secondary channel
2308*4b72b91aSCy Schubert  * to the primary channel in 6 GHz
2309*4b72b91aSCy Schubert  * @channel: Primary channel to be checked for (in global op class 131)
2310*4b72b91aSCy Schubert  * Returns: 1 = secondary channel above, -1 = secondary channel below
2311*4b72b91aSCy Schubert  */
2312*4b72b91aSCy Schubert 
2313*4b72b91aSCy Schubert int get_6ghz_sec_channel(int channel)
2314*4b72b91aSCy Schubert {
2315*4b72b91aSCy Schubert 	/*
2316*4b72b91aSCy Schubert 	 * In the 6 GHz band, primary channels are numbered as 1, 5, 9, 13.., so
2317*4b72b91aSCy Schubert 	 * the 40 MHz channels are formed with the channel pairs as (1,5),
2318*4b72b91aSCy Schubert 	 * (9,13), (17,21)..
2319*4b72b91aSCy Schubert 	 * The secondary channel for a given primary channel is below the
2320*4b72b91aSCy Schubert 	 * primary channel for the channels 5, 13, 21.. and it is above the
2321*4b72b91aSCy Schubert 	 * primary channel for the channels 1, 9, 17..
2322*4b72b91aSCy Schubert 	 */
2323*4b72b91aSCy Schubert 
2324*4b72b91aSCy Schubert 	if (((channel - 1) / 4) % 2)
2325*4b72b91aSCy Schubert 		return -1;
2326*4b72b91aSCy Schubert 	return 1;
2327*4b72b91aSCy Schubert }
2328*4b72b91aSCy Schubert 
2329*4b72b91aSCy Schubert 
233085732ac8SCy Schubert int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
233185732ac8SCy Schubert 				    size_t nei_rep_len)
233285732ac8SCy Schubert {
233385732ac8SCy Schubert 	u8 *nei_pos = nei_rep;
233485732ac8SCy Schubert 	const char *end;
233585732ac8SCy Schubert 
233685732ac8SCy Schubert 	/*
233785732ac8SCy Schubert 	 * BSS Transition Candidate List Entries - Neighbor Report elements
233885732ac8SCy Schubert 	 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
233985732ac8SCy Schubert 	 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
234085732ac8SCy Schubert 	 */
234185732ac8SCy Schubert 	while (pos) {
234285732ac8SCy Schubert 		u8 *nei_start;
234385732ac8SCy Schubert 		long int val;
234485732ac8SCy Schubert 		char *endptr, *tmp;
234585732ac8SCy Schubert 
234685732ac8SCy Schubert 		pos = os_strstr(pos, " neighbor=");
234785732ac8SCy Schubert 		if (!pos)
234885732ac8SCy Schubert 			break;
234985732ac8SCy Schubert 		if (nei_pos + 15 > nei_rep + nei_rep_len) {
235085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
235185732ac8SCy Schubert 				   "Not enough room for additional neighbor");
235285732ac8SCy Schubert 			return -1;
235385732ac8SCy Schubert 		}
235485732ac8SCy Schubert 		pos += 10;
235585732ac8SCy Schubert 
235685732ac8SCy Schubert 		nei_start = nei_pos;
235785732ac8SCy Schubert 		*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
235885732ac8SCy Schubert 		nei_pos++; /* length to be filled in */
235985732ac8SCy Schubert 
236085732ac8SCy Schubert 		if (hwaddr_aton(pos, nei_pos)) {
236185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Invalid BSSID");
236285732ac8SCy Schubert 			return -1;
236385732ac8SCy Schubert 		}
236485732ac8SCy Schubert 		nei_pos += ETH_ALEN;
236585732ac8SCy Schubert 		pos += 17;
236685732ac8SCy Schubert 		if (*pos != ',') {
236785732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing BSSID Information");
236885732ac8SCy Schubert 			return -1;
236985732ac8SCy Schubert 		}
237085732ac8SCy Schubert 		pos++;
237185732ac8SCy Schubert 
237285732ac8SCy Schubert 		val = strtol(pos, &endptr, 0);
237385732ac8SCy Schubert 		WPA_PUT_LE32(nei_pos, val);
237485732ac8SCy Schubert 		nei_pos += 4;
237585732ac8SCy Schubert 		if (*endptr != ',') {
237685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing Operating Class");
237785732ac8SCy Schubert 			return -1;
237885732ac8SCy Schubert 		}
237985732ac8SCy Schubert 		pos = endptr + 1;
238085732ac8SCy Schubert 
238185732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* Operating Class */
238285732ac8SCy Schubert 		pos = os_strchr(pos, ',');
238385732ac8SCy Schubert 		if (pos == NULL) {
238485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing Channel Number");
238585732ac8SCy Schubert 			return -1;
238685732ac8SCy Schubert 		}
238785732ac8SCy Schubert 		pos++;
238885732ac8SCy Schubert 
238985732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* Channel Number */
239085732ac8SCy Schubert 		pos = os_strchr(pos, ',');
239185732ac8SCy Schubert 		if (pos == NULL) {
239285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing PHY Type");
239385732ac8SCy Schubert 			return -1;
239485732ac8SCy Schubert 		}
239585732ac8SCy Schubert 		pos++;
239685732ac8SCy Schubert 
239785732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* PHY Type */
239885732ac8SCy Schubert 		end = os_strchr(pos, ' ');
239985732ac8SCy Schubert 		tmp = os_strchr(pos, ',');
240085732ac8SCy Schubert 		if (tmp && (!end || tmp < end)) {
240185732ac8SCy Schubert 			/* Optional Subelements (hexdump) */
240285732ac8SCy Schubert 			size_t len;
240385732ac8SCy Schubert 
240485732ac8SCy Schubert 			pos = tmp + 1;
240585732ac8SCy Schubert 			end = os_strchr(pos, ' ');
240685732ac8SCy Schubert 			if (end)
240785732ac8SCy Schubert 				len = end - pos;
240885732ac8SCy Schubert 			else
240985732ac8SCy Schubert 				len = os_strlen(pos);
241085732ac8SCy Schubert 			if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
241185732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
241285732ac8SCy Schubert 					   "Not enough room for neighbor subelements");
241385732ac8SCy Schubert 				return -1;
241485732ac8SCy Schubert 			}
241585732ac8SCy Schubert 			if (len & 0x01 ||
241685732ac8SCy Schubert 			    hexstr2bin(pos, nei_pos, len / 2) < 0) {
241785732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
241885732ac8SCy Schubert 					   "Invalid neighbor subelement info");
241985732ac8SCy Schubert 				return -1;
242085732ac8SCy Schubert 			}
242185732ac8SCy Schubert 			nei_pos += len / 2;
242285732ac8SCy Schubert 			pos = end;
242385732ac8SCy Schubert 		}
242485732ac8SCy Schubert 
242585732ac8SCy Schubert 		nei_start[1] = nei_pos - nei_start - 2;
242685732ac8SCy Schubert 	}
242785732ac8SCy Schubert 
242885732ac8SCy Schubert 	return nei_pos - nei_rep;
242985732ac8SCy Schubert }
24304bc52338SCy Schubert 
24314bc52338SCy Schubert 
24324bc52338SCy Schubert int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
24334bc52338SCy Schubert {
24344bc52338SCy Schubert 	if (!ie || ie[1] <= capab / 8)
24354bc52338SCy Schubert 		return 0;
24364bc52338SCy Schubert 	return !!(ie[2 + capab / 8] & BIT(capab % 8));
24374bc52338SCy Schubert }
2438c1d255d3SCy Schubert 
2439c1d255d3SCy Schubert 
2440c1d255d3SCy Schubert bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
2441c1d255d3SCy Schubert 			       unsigned int capab)
2442c1d255d3SCy Schubert {
2443c1d255d3SCy Schubert 	const u8 *end;
2444c1d255d3SCy Schubert 	size_t flen, i;
2445c1d255d3SCy Schubert 	u32 capabs = 0;
2446c1d255d3SCy Schubert 
2447c1d255d3SCy Schubert 	if (!rsnxe || rsnxe_len == 0)
2448c1d255d3SCy Schubert 		return false;
2449c1d255d3SCy Schubert 	end = rsnxe + rsnxe_len;
2450c1d255d3SCy Schubert 	flen = (rsnxe[0] & 0x0f) + 1;
2451c1d255d3SCy Schubert 	if (rsnxe + flen > end)
2452c1d255d3SCy Schubert 		return false;
2453c1d255d3SCy Schubert 	if (flen > 4)
2454c1d255d3SCy Schubert 		flen = 4;
2455c1d255d3SCy Schubert 	for (i = 0; i < flen; i++)
2456c1d255d3SCy Schubert 		capabs |= rsnxe[i] << (8 * i);
2457c1d255d3SCy Schubert 
2458c1d255d3SCy Schubert 	return capabs & BIT(capab);
2459c1d255d3SCy Schubert }
2460c1d255d3SCy Schubert 
2461c1d255d3SCy Schubert 
2462c1d255d3SCy Schubert bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
2463c1d255d3SCy Schubert {
2464c1d255d3SCy Schubert 	return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL,
2465c1d255d3SCy Schubert 					 rsnxe ? rsnxe[1] : 0, capab);
2466c1d255d3SCy Schubert }
2467c1d255d3SCy Schubert 
2468c1d255d3SCy Schubert 
2469c1d255d3SCy Schubert void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
2470c1d255d3SCy Schubert 			      int primary_channel,
2471c1d255d3SCy Schubert 			      struct ieee80211_edmg_config *edmg)
2472c1d255d3SCy Schubert {
2473c1d255d3SCy Schubert 	if (!edmg_enable) {
2474c1d255d3SCy Schubert 		edmg->channels = 0;
2475c1d255d3SCy Schubert 		edmg->bw_config = 0;
2476c1d255d3SCy Schubert 		return;
2477c1d255d3SCy Schubert 	}
2478c1d255d3SCy Schubert 
2479c1d255d3SCy Schubert 	/* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
2480c1d255d3SCy Schubert 	switch (edmg_channel) {
2481c1d255d3SCy Schubert 	case EDMG_CHANNEL_9:
2482c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
2483c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
2484c1d255d3SCy Schubert 		return;
2485c1d255d3SCy Schubert 	case EDMG_CHANNEL_10:
2486c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
2487c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
2488c1d255d3SCy Schubert 		return;
2489c1d255d3SCy Schubert 	case EDMG_CHANNEL_11:
2490c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
2491c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
2492c1d255d3SCy Schubert 		return;
2493c1d255d3SCy Schubert 	case EDMG_CHANNEL_12:
2494c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
2495c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
2496c1d255d3SCy Schubert 		return;
2497c1d255d3SCy Schubert 	case EDMG_CHANNEL_13:
2498c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
2499c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
2500c1d255d3SCy Schubert 		return;
2501c1d255d3SCy Schubert 	default:
2502c1d255d3SCy Schubert 		if (primary_channel > 0 && primary_channel < 7) {
2503c1d255d3SCy Schubert 			edmg->channels = BIT(primary_channel - 1);
2504c1d255d3SCy Schubert 			edmg->bw_config = EDMG_BW_CONFIG_4;
2505c1d255d3SCy Schubert 		} else {
2506c1d255d3SCy Schubert 			edmg->channels = 0;
2507c1d255d3SCy Schubert 			edmg->bw_config = 0;
2508c1d255d3SCy Schubert 		}
2509c1d255d3SCy Schubert 		break;
2510c1d255d3SCy Schubert 	}
2511c1d255d3SCy Schubert }
2512c1d255d3SCy Schubert 
2513c1d255d3SCy Schubert 
2514c1d255d3SCy Schubert /* Check if the requested EDMG configuration is a subset of the allowed
2515c1d255d3SCy Schubert  * EDMG configuration. */
2516c1d255d3SCy Schubert int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
2517c1d255d3SCy Schubert 			    struct ieee80211_edmg_config requested)
2518c1d255d3SCy Schubert {
2519c1d255d3SCy Schubert 	/*
2520c1d255d3SCy Schubert 	 * The validation check if the requested EDMG configuration
2521c1d255d3SCy Schubert 	 * is a subset of the allowed EDMG configuration:
2522c1d255d3SCy Schubert 	 * 1. Check that the requested channels are part (set) of the allowed
2523c1d255d3SCy Schubert 	 * channels.
2524c1d255d3SCy Schubert 	 * 2. P802.11ay defines the values of bw_config between 4 and 15.
2525c1d255d3SCy Schubert 	 * (bw config % 4) will give us 4 groups inside bw_config definition,
2526c1d255d3SCy Schubert 	 * inside each group we can check the subset just by comparing the
2527c1d255d3SCy Schubert 	 * bw_config value.
2528c1d255d3SCy Schubert 	 * Between this 4 groups, there is no subset relation - as a result of
2529c1d255d3SCy Schubert 	 * the P802.11ay definition.
2530c1d255d3SCy Schubert 	 * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
2531c1d255d3SCy Schubert 	 */
2532c1d255d3SCy Schubert 	if (((requested.channels & allowed.channels) != requested.channels) ||
2533c1d255d3SCy Schubert 	    ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
2534c1d255d3SCy Schubert 	    requested.bw_config > allowed.bw_config)
2535c1d255d3SCy Schubert 		return 0;
2536c1d255d3SCy Schubert 
2537c1d255d3SCy Schubert 	return 1;
2538c1d255d3SCy Schubert }
2539c1d255d3SCy Schubert 
2540c1d255d3SCy Schubert 
2541c1d255d3SCy Schubert int op_class_to_bandwidth(u8 op_class)
2542c1d255d3SCy Schubert {
2543c1d255d3SCy Schubert 	switch (op_class) {
2544c1d255d3SCy Schubert 	case 81:
2545c1d255d3SCy Schubert 	case 82:
2546c1d255d3SCy Schubert 		return 20;
2547c1d255d3SCy Schubert 	case 83: /* channels 1..9; 40 MHz */
2548c1d255d3SCy Schubert 	case 84: /* channels 5..13; 40 MHz */
2549c1d255d3SCy Schubert 		return 40;
2550c1d255d3SCy Schubert 	case 115: /* channels 36,40,44,48; indoor only */
2551c1d255d3SCy Schubert 		return 20;
2552c1d255d3SCy Schubert 	case 116: /* channels 36,44; 40 MHz; indoor only */
2553c1d255d3SCy Schubert 	case 117: /* channels 40,48; 40 MHz; indoor only */
2554c1d255d3SCy Schubert 		return 40;
2555c1d255d3SCy Schubert 	case 118: /* channels 52,56,60,64; dfs */
2556c1d255d3SCy Schubert 		return 20;
2557c1d255d3SCy Schubert 	case 119: /* channels 52,60; 40 MHz; dfs */
2558c1d255d3SCy Schubert 	case 120: /* channels 56,64; 40 MHz; dfs */
2559c1d255d3SCy Schubert 		return 40;
2560c1d255d3SCy Schubert 	case 121: /* channels 100-140 */
2561c1d255d3SCy Schubert 		return 20;
2562c1d255d3SCy Schubert 	case 122: /* channels 100-142; 40 MHz */
2563c1d255d3SCy Schubert 	case 123: /* channels 104-136; 40 MHz */
2564c1d255d3SCy Schubert 		return 40;
2565c1d255d3SCy Schubert 	case 124: /* channels 149,153,157,161 */
2566c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,173,177 */
2567c1d255d3SCy Schubert 		return 20;
2568c1d255d3SCy Schubert 	case 126: /* channels 149,157,161,165,169,173; 40 MHz */
2569c1d255d3SCy Schubert 	case 127: /* channels 153..177; 40 MHz */
2570c1d255d3SCy Schubert 		return 40;
2571c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
2572c1d255d3SCy Schubert 		return 80;
2573c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
2574c1d255d3SCy Schubert 		return 160;
2575c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
2576c1d255d3SCy Schubert 		return 80;
2577c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
2578c1d255d3SCy Schubert 		return 20;
2579c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
2580c1d255d3SCy Schubert 		return 40;
2581c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
2582c1d255d3SCy Schubert 		return 80;
2583c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
2584c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
2585c1d255d3SCy Schubert 		return 160;
2586c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
2587c1d255d3SCy Schubert 		return 20;
2588c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
2589c1d255d3SCy Schubert 		return 2160;
2590c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
2591c1d255d3SCy Schubert 		return 4320;
2592c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
2593c1d255d3SCy Schubert 		return 6480;
2594c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
2595c1d255d3SCy Schubert 		return 8640;
2596c1d255d3SCy Schubert 	}
2597c1d255d3SCy Schubert 
2598c1d255d3SCy Schubert 	return 20;
2599c1d255d3SCy Schubert }
2600c1d255d3SCy Schubert 
2601c1d255d3SCy Schubert 
2602c1d255d3SCy Schubert int op_class_to_ch_width(u8 op_class)
2603c1d255d3SCy Schubert {
2604c1d255d3SCy Schubert 	switch (op_class) {
2605c1d255d3SCy Schubert 	case 81:
2606c1d255d3SCy Schubert 	case 82:
2607c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2608c1d255d3SCy Schubert 	case 83: /* channels 1..9; 40 MHz */
2609c1d255d3SCy Schubert 	case 84: /* channels 5..13; 40 MHz */
2610c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2611c1d255d3SCy Schubert 	case 115: /* channels 36,40,44,48; indoor only */
2612c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2613c1d255d3SCy Schubert 	case 116: /* channels 36,44; 40 MHz; indoor only */
2614c1d255d3SCy Schubert 	case 117: /* channels 40,48; 40 MHz; indoor only */
2615c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2616c1d255d3SCy Schubert 	case 118: /* channels 52,56,60,64; dfs */
2617c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2618c1d255d3SCy Schubert 	case 119: /* channels 52,60; 40 MHz; dfs */
2619c1d255d3SCy Schubert 	case 120: /* channels 56,64; 40 MHz; dfs */
2620c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2621c1d255d3SCy Schubert 	case 121: /* channels 100-140 */
2622c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2623c1d255d3SCy Schubert 	case 122: /* channels 100-142; 40 MHz */
2624c1d255d3SCy Schubert 	case 123: /* channels 104-136; 40 MHz */
2625c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2626c1d255d3SCy Schubert 	case 124: /* channels 149,153,157,161 */
2627c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,171 */
2628c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2629c1d255d3SCy Schubert 	case 126: /* channels 149,157,165, 173; 40 MHz */
2630c1d255d3SCy Schubert 	case 127: /* channels 153,161,169,177; 40 MHz */
2631c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2632c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
2633c1d255d3SCy Schubert 		return CHANWIDTH_80MHZ;
2634c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
2635c1d255d3SCy Schubert 		return CHANWIDTH_160MHZ;
2636c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
2637c1d255d3SCy Schubert 		return CHANWIDTH_80P80MHZ;
2638c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
2639c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2640c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
2641c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2642c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
2643c1d255d3SCy Schubert 		return CHANWIDTH_80MHZ;
2644c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
2645c1d255d3SCy Schubert 		return CHANWIDTH_160MHZ;
2646c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
2647c1d255d3SCy Schubert 		return CHANWIDTH_80P80MHZ;
2648c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
2649c1d255d3SCy Schubert 		return CHANWIDTH_USE_HT;
2650c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
2651c1d255d3SCy Schubert 		return CHANWIDTH_2160MHZ;
2652c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
2653c1d255d3SCy Schubert 		return CHANWIDTH_4320MHZ;
2654c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
2655c1d255d3SCy Schubert 		return CHANWIDTH_6480MHZ;
2656c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
2657c1d255d3SCy Schubert 		return CHANWIDTH_8640MHZ;
2658c1d255d3SCy Schubert 	}
2659c1d255d3SCy Schubert 	return CHANWIDTH_USE_HT;
2660c1d255d3SCy Schubert }
2661c1d255d3SCy Schubert 
2662c1d255d3SCy Schubert 
2663c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
2664c1d255d3SCy Schubert 				       u8 eid, u8 eid_ext,
2665c1d255d3SCy Schubert 				       const u8 *data, u8 len)
2666c1d255d3SCy Schubert {
2667c1d255d3SCy Schubert 	struct frag_ies_info *frag_ies = &elems->frag_ies;
2668c1d255d3SCy Schubert 	struct wpabuf *buf;
2669c1d255d3SCy Schubert 	unsigned int i;
2670c1d255d3SCy Schubert 
2671c1d255d3SCy Schubert 	if (!elems || !data || !len)
2672c1d255d3SCy Schubert 		return NULL;
2673c1d255d3SCy Schubert 
2674c1d255d3SCy Schubert 	buf = wpabuf_alloc_copy(data, len);
2675c1d255d3SCy Schubert 	if (!buf)
2676c1d255d3SCy Schubert 		return NULL;
2677c1d255d3SCy Schubert 
2678c1d255d3SCy Schubert 	for (i = 0; i < frag_ies->n_frags; i++) {
2679c1d255d3SCy Schubert 		int ret;
2680c1d255d3SCy Schubert 
2681c1d255d3SCy Schubert 		if (frag_ies->frags[i].eid != eid ||
2682c1d255d3SCy Schubert 		    frag_ies->frags[i].eid_ext != eid_ext)
2683c1d255d3SCy Schubert 			continue;
2684c1d255d3SCy Schubert 
2685c1d255d3SCy Schubert 		ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
2686c1d255d3SCy Schubert 		if (ret < 0) {
2687c1d255d3SCy Schubert 			wpabuf_free(buf);
2688c1d255d3SCy Schubert 			return NULL;
2689c1d255d3SCy Schubert 		}
2690c1d255d3SCy Schubert 
2691c1d255d3SCy Schubert 		/* Copy only the fragment data (without the EID and length) */
2692c1d255d3SCy Schubert 		wpabuf_put_data(buf, frag_ies->frags[i].ie,
2693c1d255d3SCy Schubert 				frag_ies->frags[i].ie_len);
2694c1d255d3SCy Schubert 	}
2695c1d255d3SCy Schubert 
2696c1d255d3SCy Schubert 	return buf;
2697c1d255d3SCy Schubert }
2698c1d255d3SCy Schubert 
2699c1d255d3SCy Schubert 
2700c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
2701c1d255d3SCy Schubert 				  u8 eid, u8 eid_ext)
2702c1d255d3SCy Schubert {
2703c1d255d3SCy Schubert 	const u8 *data;
2704c1d255d3SCy Schubert 	u8 len;
2705c1d255d3SCy Schubert 
2706c1d255d3SCy Schubert 	/*
2707c1d255d3SCy Schubert 	 * TODO: Defragmentation mechanism can be supported for all IEs. For now
2708c1d255d3SCy Schubert 	 * handle only those that are used (or use ieee802_11_defrag_data()).
2709c1d255d3SCy Schubert 	 */
2710c1d255d3SCy Schubert 	switch (eid) {
2711c1d255d3SCy Schubert 	case WLAN_EID_EXTENSION:
2712c1d255d3SCy Schubert 		switch (eid_ext) {
2713c1d255d3SCy Schubert 		case WLAN_EID_EXT_FILS_HLP_CONTAINER:
2714c1d255d3SCy Schubert 			data = elems->fils_hlp;
2715c1d255d3SCy Schubert 			len = elems->fils_hlp_len;
2716c1d255d3SCy Schubert 			break;
2717c1d255d3SCy Schubert 		case WLAN_EID_EXT_WRAPPED_DATA:
2718c1d255d3SCy Schubert 			data = elems->wrapped_data;
2719c1d255d3SCy Schubert 			len = elems->wrapped_data_len;
2720c1d255d3SCy Schubert 			break;
2721c1d255d3SCy Schubert 		default:
2722c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
2723c1d255d3SCy Schubert 				   "Defragmentation not supported. eid_ext=%u",
2724c1d255d3SCy Schubert 				   eid_ext);
2725c1d255d3SCy Schubert 			return NULL;
2726c1d255d3SCy Schubert 		}
2727c1d255d3SCy Schubert 		break;
2728c1d255d3SCy Schubert 	default:
2729c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2730c1d255d3SCy Schubert 			   "Defragmentation not supported. eid=%u", eid);
2731c1d255d3SCy Schubert 		return NULL;
2732c1d255d3SCy Schubert 	}
2733c1d255d3SCy Schubert 
2734c1d255d3SCy Schubert 	return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
2735c1d255d3SCy Schubert }
2736