xref: /freebsd/contrib/wpa/src/common/ieee802_11_common.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 
ieee802_11_parse_vendor_specific(const u8 * pos,size_t elen,struct ieee802_11_elems * elems,int show_errors)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 
ieee802_11_parse_mle(const u8 * pos,size_t elen,size_t ** total_len,struct ieee802_11_elems * elems,int show_errors)202*a90b9d01SCy Schubert static int ieee802_11_parse_mle(const u8 *pos, size_t elen, size_t **total_len,
20385732ac8SCy Schubert 				struct ieee802_11_elems *elems,
20485732ac8SCy Schubert 				int show_errors)
20585732ac8SCy Schubert {
206*a90b9d01SCy Schubert 	u8 mle_type = pos[0] & MULTI_LINK_CONTROL_TYPE_MASK;
207*a90b9d01SCy Schubert 
208*a90b9d01SCy Schubert 	switch (mle_type) {
209*a90b9d01SCy Schubert 	case MULTI_LINK_CONTROL_TYPE_BASIC:
210*a90b9d01SCy Schubert 		elems->basic_mle = pos;
211*a90b9d01SCy Schubert 		elems->basic_mle_len = elen;
212*a90b9d01SCy Schubert 		*total_len = &elems->basic_mle_len;
213*a90b9d01SCy Schubert 		break;
214*a90b9d01SCy Schubert 	case MULTI_LINK_CONTROL_TYPE_PROBE_REQ:
215*a90b9d01SCy Schubert 		elems->probe_req_mle = pos;
216*a90b9d01SCy Schubert 		elems->probe_req_mle_len = elen;
217*a90b9d01SCy Schubert 		*total_len = &elems->probe_req_mle_len;
218*a90b9d01SCy Schubert 		break;
219*a90b9d01SCy Schubert 	case MULTI_LINK_CONTROL_TYPE_RECONF:
220*a90b9d01SCy Schubert 		elems->reconf_mle = pos;
221*a90b9d01SCy Schubert 		elems->reconf_mle_len = elen;
222*a90b9d01SCy Schubert 		*total_len = &elems->reconf_mle_len;
223*a90b9d01SCy Schubert 		break;
224*a90b9d01SCy Schubert 	case MULTI_LINK_CONTROL_TYPE_TDLS:
225*a90b9d01SCy Schubert 		elems->tdls_mle = pos;
226*a90b9d01SCy Schubert 		elems->tdls_mle_len = elen;
227*a90b9d01SCy Schubert 		*total_len = &elems->tdls_mle_len;
228*a90b9d01SCy Schubert 		break;
229*a90b9d01SCy Schubert 	case MULTI_LINK_CONTROL_TYPE_PRIOR_ACCESS:
230*a90b9d01SCy Schubert 		elems->prior_access_mle = pos;
231*a90b9d01SCy Schubert 		elems->prior_access_mle_len = elen;
232*a90b9d01SCy Schubert 		*total_len = &elems->prior_access_mle_len;
233*a90b9d01SCy Schubert 		break;
234*a90b9d01SCy Schubert 	default:
235*a90b9d01SCy Schubert 		if (show_errors) {
236*a90b9d01SCy Schubert 			wpa_printf(MSG_MSGDUMP,
237*a90b9d01SCy Schubert 				   "Unknown Multi-Link element type %u",
238*a90b9d01SCy Schubert 				   mle_type);
239*a90b9d01SCy Schubert 		}
240*a90b9d01SCy Schubert 		return -1;
241*a90b9d01SCy Schubert 	}
242*a90b9d01SCy Schubert 
243*a90b9d01SCy Schubert 	return 0;
244*a90b9d01SCy Schubert }
245*a90b9d01SCy Schubert 
246*a90b9d01SCy Schubert 
ieee802_11_fragments_length(struct ieee802_11_elems * elems,const u8 * start,size_t len)247*a90b9d01SCy Schubert static size_t ieee802_11_fragments_length(struct ieee802_11_elems *elems,
248*a90b9d01SCy Schubert 					  const u8 *start, size_t len)
249*a90b9d01SCy Schubert {
250*a90b9d01SCy Schubert 	const struct element *elem;
251*a90b9d01SCy Schubert 	size_t frags_len = 0;
252*a90b9d01SCy Schubert 
253*a90b9d01SCy Schubert 	for_each_element(elem, start, len) {
254*a90b9d01SCy Schubert 		if (elem->id != WLAN_EID_FRAGMENT)
255*a90b9d01SCy Schubert 			break;
256*a90b9d01SCy Schubert 
257*a90b9d01SCy Schubert 		frags_len += elem->datalen + 2;
258*a90b9d01SCy Schubert 		elems->num_frag_elems++;
259*a90b9d01SCy Schubert 	}
260*a90b9d01SCy Schubert 
261*a90b9d01SCy Schubert 	return frags_len;
262*a90b9d01SCy Schubert }
263*a90b9d01SCy Schubert 
264*a90b9d01SCy Schubert 
ieee802_11_parse_extension(const u8 * pos,size_t elen,struct ieee802_11_elems * elems,const u8 * start,size_t len,int show_errors)265*a90b9d01SCy Schubert static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
266*a90b9d01SCy Schubert 				      struct ieee802_11_elems *elems,
267*a90b9d01SCy Schubert 				      const u8 *start, size_t len,
268*a90b9d01SCy Schubert 				      int show_errors)
269*a90b9d01SCy Schubert {
27085732ac8SCy Schubert 	u8 ext_id;
271*a90b9d01SCy Schubert 	size_t *total_len = NULL;
27285732ac8SCy Schubert 
27385732ac8SCy Schubert 	if (elen < 1) {
27485732ac8SCy Schubert 		if (show_errors) {
27585732ac8SCy Schubert 			wpa_printf(MSG_MSGDUMP,
27685732ac8SCy Schubert 				   "short information element (Ext)");
27785732ac8SCy Schubert 		}
27885732ac8SCy Schubert 		return -1;
27985732ac8SCy Schubert 	}
28085732ac8SCy Schubert 
28185732ac8SCy Schubert 	ext_id = *pos++;
28285732ac8SCy Schubert 	elen--;
28385732ac8SCy Schubert 
28485732ac8SCy Schubert 	switch (ext_id) {
28585732ac8SCy Schubert 	case WLAN_EID_EXT_ASSOC_DELAY_INFO:
28685732ac8SCy Schubert 		if (elen != 1)
28785732ac8SCy Schubert 			break;
28885732ac8SCy Schubert 		elems->assoc_delay_info = pos;
28985732ac8SCy Schubert 		break;
29085732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_REQ_PARAMS:
29185732ac8SCy Schubert 		if (elen < 3)
29285732ac8SCy Schubert 			break;
29385732ac8SCy Schubert 		elems->fils_req_params = pos;
29485732ac8SCy Schubert 		elems->fils_req_params_len = elen;
29585732ac8SCy Schubert 		break;
29685732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_KEY_CONFIRM:
29785732ac8SCy Schubert 		elems->fils_key_confirm = pos;
29885732ac8SCy Schubert 		elems->fils_key_confirm_len = elen;
29985732ac8SCy Schubert 		break;
30085732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_SESSION:
30185732ac8SCy Schubert 		if (elen != FILS_SESSION_LEN)
30285732ac8SCy Schubert 			break;
30385732ac8SCy Schubert 		elems->fils_session = pos;
30485732ac8SCy Schubert 		break;
30585732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_HLP_CONTAINER:
30685732ac8SCy Schubert 		if (elen < 2 * ETH_ALEN)
30785732ac8SCy Schubert 			break;
30885732ac8SCy Schubert 		elems->fils_hlp = pos;
30985732ac8SCy Schubert 		elems->fils_hlp_len = elen;
310*a90b9d01SCy Schubert 		total_len = &elems->fils_hlp_len;
31185732ac8SCy Schubert 		break;
31285732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
31385732ac8SCy Schubert 		if (elen < 1)
31485732ac8SCy Schubert 			break;
31585732ac8SCy Schubert 		elems->fils_ip_addr_assign = pos;
31685732ac8SCy Schubert 		elems->fils_ip_addr_assign_len = elen;
31785732ac8SCy Schubert 		break;
31885732ac8SCy Schubert 	case WLAN_EID_EXT_KEY_DELIVERY:
31985732ac8SCy Schubert 		if (elen < WPA_KEY_RSC_LEN)
32085732ac8SCy Schubert 			break;
32185732ac8SCy Schubert 		elems->key_delivery = pos;
32285732ac8SCy Schubert 		elems->key_delivery_len = elen;
32385732ac8SCy Schubert 		break;
324c1d255d3SCy Schubert 	case WLAN_EID_EXT_WRAPPED_DATA:
325c1d255d3SCy Schubert 		elems->wrapped_data = pos;
326c1d255d3SCy Schubert 		elems->wrapped_data_len = elen;
327*a90b9d01SCy Schubert 		total_len = &elems->wrapped_data_len;
32885732ac8SCy Schubert 		break;
32985732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_PUBLIC_KEY:
33085732ac8SCy Schubert 		if (elen < 1)
33185732ac8SCy Schubert 			break;
33285732ac8SCy Schubert 		elems->fils_pk = pos;
33385732ac8SCy Schubert 		elems->fils_pk_len = elen;
33485732ac8SCy Schubert 		break;
33585732ac8SCy Schubert 	case WLAN_EID_EXT_FILS_NONCE:
33685732ac8SCy Schubert 		if (elen != FILS_NONCE_LEN)
33785732ac8SCy Schubert 			break;
33885732ac8SCy Schubert 		elems->fils_nonce = pos;
33985732ac8SCy Schubert 		break;
34085732ac8SCy Schubert 	case WLAN_EID_EXT_OWE_DH_PARAM:
34185732ac8SCy Schubert 		if (elen < 2)
34285732ac8SCy Schubert 			break;
34385732ac8SCy Schubert 		elems->owe_dh = pos;
34485732ac8SCy Schubert 		elems->owe_dh_len = elen;
34585732ac8SCy Schubert 		break;
34685732ac8SCy Schubert 	case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
34785732ac8SCy Schubert 		elems->password_id = pos;
34885732ac8SCy Schubert 		elems->password_id_len = elen;
34985732ac8SCy Schubert 		break;
3504bc52338SCy Schubert 	case WLAN_EID_EXT_HE_CAPABILITIES:
3514bc52338SCy Schubert 		elems->he_capabilities = pos;
3524bc52338SCy Schubert 		elems->he_capabilities_len = elen;
3534bc52338SCy Schubert 		break;
354206b73d0SCy Schubert 	case WLAN_EID_EXT_HE_OPERATION:
355206b73d0SCy Schubert 		elems->he_operation = pos;
356206b73d0SCy Schubert 		elems->he_operation_len = elen;
357206b73d0SCy Schubert 		break;
3584bc52338SCy Schubert 	case WLAN_EID_EXT_OCV_OCI:
3594bc52338SCy Schubert 		elems->oci = pos;
3604bc52338SCy Schubert 		elems->oci_len = elen;
3614bc52338SCy Schubert 		break;
362c1d255d3SCy Schubert 	case WLAN_EID_EXT_SHORT_SSID_LIST:
363c1d255d3SCy Schubert 		elems->short_ssid_list = pos;
364c1d255d3SCy Schubert 		elems->short_ssid_list_len = elen;
365c1d255d3SCy Schubert 		break;
366c1d255d3SCy Schubert 	case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
367c1d255d3SCy Schubert 		if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
368c1d255d3SCy Schubert 			break;
369c1d255d3SCy Schubert 		elems->he_6ghz_band_cap = pos;
370c1d255d3SCy Schubert 		break;
371c1d255d3SCy Schubert 	case WLAN_EID_EXT_PASN_PARAMS:
372c1d255d3SCy Schubert 		elems->pasn_params = pos;
373c1d255d3SCy Schubert 		elems->pasn_params_len = elen;
374c1d255d3SCy Schubert 		break;
375*a90b9d01SCy Schubert 	case WLAN_EID_EXT_EHT_CAPABILITIES:
376*a90b9d01SCy Schubert 		elems->eht_capabilities = pos;
377*a90b9d01SCy Schubert 		elems->eht_capabilities_len = elen;
378*a90b9d01SCy Schubert 		break;
379*a90b9d01SCy Schubert 	case WLAN_EID_EXT_EHT_OPERATION:
380*a90b9d01SCy Schubert 		elems->eht_operation = pos;
381*a90b9d01SCy Schubert 		elems->eht_operation_len = elen;
382*a90b9d01SCy Schubert 		break;
383*a90b9d01SCy Schubert 	case WLAN_EID_EXT_MULTI_LINK:
384*a90b9d01SCy Schubert 		if (elen < 2)
385*a90b9d01SCy Schubert 			break;
386*a90b9d01SCy Schubert 		if (ieee802_11_parse_mle(pos, elen, &total_len, elems,
387*a90b9d01SCy Schubert 					 show_errors))
388*a90b9d01SCy Schubert 			return -1;
389*a90b9d01SCy Schubert 		break;
390*a90b9d01SCy Schubert 	case WLAN_EID_EXT_KNOWN_BSSID:
391*a90b9d01SCy Schubert 		elems->mbssid_known_bss = pos;
392*a90b9d01SCy Schubert 		elems->mbssid_known_bss_len = elen;
393*a90b9d01SCy Schubert 		break;
39485732ac8SCy Schubert 	default:
39585732ac8SCy Schubert 		if (show_errors) {
39685732ac8SCy Schubert 			wpa_printf(MSG_MSGDUMP,
39785732ac8SCy Schubert 				   "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
39885732ac8SCy Schubert 				   ext_id, (unsigned int) elen);
39985732ac8SCy Schubert 		}
40085732ac8SCy Schubert 		return -1;
40185732ac8SCy Schubert 	}
40285732ac8SCy Schubert 
403*a90b9d01SCy Schubert 	if (elen == 254 && total_len)
404*a90b9d01SCy Schubert 		*total_len += ieee802_11_fragments_length(
405*a90b9d01SCy Schubert 			elems, pos + elen, (start + len) - (pos + elen));
406c1d255d3SCy Schubert 
40785732ac8SCy Schubert 	return 0;
40885732ac8SCy Schubert }
40985732ac8SCy Schubert 
41085732ac8SCy Schubert 
__ieee802_11_parse_elems(const u8 * start,size_t len,struct ieee802_11_elems * elems,int show_errors)411*a90b9d01SCy Schubert static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len,
41239beb93cSSam Leffler 					 struct ieee802_11_elems *elems,
41339beb93cSSam Leffler 					 int show_errors)
41439beb93cSSam Leffler {
4154bc52338SCy Schubert 	const struct element *elem;
41639beb93cSSam Leffler 	int unknown = 0;
41739beb93cSSam Leffler 
4184bc52338SCy Schubert 	if (!start)
4194bc52338SCy Schubert 		return ParseOK;
42039beb93cSSam Leffler 
4214bc52338SCy Schubert 	for_each_element(elem, start, len) {
4224bc52338SCy Schubert 		u8 id = elem->id, elen = elem->datalen;
4234bc52338SCy Schubert 		const u8 *pos = elem->data;
424*a90b9d01SCy Schubert 		size_t *total_len = NULL;
425*a90b9d01SCy Schubert 
426*a90b9d01SCy Schubert 		if (id == WLAN_EID_FRAGMENT && elems->num_frag_elems > 0) {
427*a90b9d01SCy Schubert 			elems->num_frag_elems--;
428*a90b9d01SCy Schubert 			continue;
429*a90b9d01SCy Schubert 		}
430*a90b9d01SCy Schubert 		elems->num_frag_elems = 0;
43139beb93cSSam Leffler 
43239beb93cSSam Leffler 		switch (id) {
43339beb93cSSam Leffler 		case WLAN_EID_SSID:
434325151a3SRui Paulo 			if (elen > SSID_MAX_LEN) {
435325151a3SRui Paulo 				wpa_printf(MSG_DEBUG,
436325151a3SRui Paulo 					   "Ignored too long SSID element (elen=%u)",
437325151a3SRui Paulo 					   elen);
438325151a3SRui Paulo 				break;
439325151a3SRui Paulo 			}
440c1d255d3SCy Schubert 			if (elems->ssid) {
441c1d255d3SCy Schubert 				wpa_printf(MSG_MSGDUMP,
442c1d255d3SCy Schubert 					   "Ignored duplicated SSID element");
443c1d255d3SCy Schubert 				break;
444c1d255d3SCy Schubert 			}
44539beb93cSSam Leffler 			elems->ssid = pos;
44639beb93cSSam Leffler 			elems->ssid_len = elen;
44739beb93cSSam Leffler 			break;
44839beb93cSSam Leffler 		case WLAN_EID_SUPP_RATES:
44939beb93cSSam Leffler 			elems->supp_rates = pos;
45039beb93cSSam Leffler 			elems->supp_rates_len = elen;
45139beb93cSSam Leffler 			break;
45239beb93cSSam Leffler 		case WLAN_EID_DS_PARAMS:
453325151a3SRui Paulo 			if (elen < 1)
454325151a3SRui Paulo 				break;
45539beb93cSSam Leffler 			elems->ds_params = pos;
45639beb93cSSam Leffler 			break;
45739beb93cSSam Leffler 		case WLAN_EID_CF_PARAMS:
45839beb93cSSam Leffler 		case WLAN_EID_TIM:
45939beb93cSSam Leffler 			break;
46039beb93cSSam Leffler 		case WLAN_EID_CHALLENGE:
46139beb93cSSam Leffler 			elems->challenge = pos;
46239beb93cSSam Leffler 			elems->challenge_len = elen;
46339beb93cSSam Leffler 			break;
46439beb93cSSam Leffler 		case WLAN_EID_ERP_INFO:
465325151a3SRui Paulo 			if (elen < 1)
466325151a3SRui Paulo 				break;
46739beb93cSSam Leffler 			elems->erp_info = pos;
46839beb93cSSam Leffler 			break;
46939beb93cSSam Leffler 		case WLAN_EID_EXT_SUPP_RATES:
47039beb93cSSam Leffler 			elems->ext_supp_rates = pos;
47139beb93cSSam Leffler 			elems->ext_supp_rates_len = elen;
47239beb93cSSam Leffler 			break;
47339beb93cSSam Leffler 		case WLAN_EID_VENDOR_SPECIFIC:
47439beb93cSSam Leffler 			if (ieee802_11_parse_vendor_specific(pos, elen,
47539beb93cSSam Leffler 							     elems,
47639beb93cSSam Leffler 							     show_errors))
47739beb93cSSam Leffler 				unknown++;
47839beb93cSSam Leffler 			break;
47939beb93cSSam Leffler 		case WLAN_EID_RSN:
48039beb93cSSam Leffler 			elems->rsn_ie = pos;
48139beb93cSSam Leffler 			elems->rsn_ie_len = elen;
48239beb93cSSam Leffler 			break;
483c1d255d3SCy Schubert 		case WLAN_EID_RSNX:
484c1d255d3SCy Schubert 			elems->rsnxe = pos;
485c1d255d3SCy Schubert 			elems->rsnxe_len = elen;
486c1d255d3SCy Schubert 			break;
48739beb93cSSam Leffler 		case WLAN_EID_PWR_CAPABILITY:
48885732ac8SCy Schubert 			if (elen < 2)
48985732ac8SCy Schubert 				break;
49085732ac8SCy Schubert 			elems->power_capab = pos;
49185732ac8SCy Schubert 			elems->power_capab_len = elen;
49239beb93cSSam Leffler 			break;
49339beb93cSSam Leffler 		case WLAN_EID_SUPPORTED_CHANNELS:
49439beb93cSSam Leffler 			elems->supp_channels = pos;
49539beb93cSSam Leffler 			elems->supp_channels_len = elen;
49639beb93cSSam Leffler 			break;
49739beb93cSSam Leffler 		case WLAN_EID_MOBILITY_DOMAIN:
498325151a3SRui Paulo 			if (elen < sizeof(struct rsn_mdie))
499325151a3SRui Paulo 				break;
50039beb93cSSam Leffler 			elems->mdie = pos;
50139beb93cSSam Leffler 			elems->mdie_len = elen;
50239beb93cSSam Leffler 			break;
50339beb93cSSam Leffler 		case WLAN_EID_FAST_BSS_TRANSITION:
504325151a3SRui Paulo 			if (elen < sizeof(struct rsn_ftie))
505325151a3SRui Paulo 				break;
50639beb93cSSam Leffler 			elems->ftie = pos;
50739beb93cSSam Leffler 			elems->ftie_len = elen;
508*a90b9d01SCy Schubert 			elems->fte_defrag_len = elen;
509*a90b9d01SCy Schubert 			total_len = &elems->fte_defrag_len;
51039beb93cSSam Leffler 			break;
51139beb93cSSam Leffler 		case WLAN_EID_TIMEOUT_INTERVAL:
512325151a3SRui Paulo 			if (elen != 5)
513325151a3SRui Paulo 				break;
51439beb93cSSam Leffler 			elems->timeout_int = pos;
51539beb93cSSam Leffler 			break;
51639beb93cSSam Leffler 		case WLAN_EID_HT_CAP:
517325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_ht_capabilities))
518325151a3SRui Paulo 				break;
51939beb93cSSam Leffler 			elems->ht_capabilities = pos;
52039beb93cSSam Leffler 			break;
52139beb93cSSam Leffler 		case WLAN_EID_HT_OPERATION:
522325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_ht_operation))
523325151a3SRui Paulo 				break;
52439beb93cSSam Leffler 			elems->ht_operation = pos;
52539beb93cSSam Leffler 			break;
5265b9c547cSRui Paulo 		case WLAN_EID_MESH_CONFIG:
5275b9c547cSRui Paulo 			elems->mesh_config = pos;
5285b9c547cSRui Paulo 			elems->mesh_config_len = elen;
5295b9c547cSRui Paulo 			break;
5305b9c547cSRui Paulo 		case WLAN_EID_MESH_ID:
5315b9c547cSRui Paulo 			elems->mesh_id = pos;
5325b9c547cSRui Paulo 			elems->mesh_id_len = elen;
5335b9c547cSRui Paulo 			break;
5345b9c547cSRui Paulo 		case WLAN_EID_PEER_MGMT:
5355b9c547cSRui Paulo 			elems->peer_mgmt = pos;
5365b9c547cSRui Paulo 			elems->peer_mgmt_len = elen;
5375b9c547cSRui Paulo 			break;
538f05cddf9SRui Paulo 		case WLAN_EID_VHT_CAP:
539325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_vht_capabilities))
540325151a3SRui Paulo 				break;
541f05cddf9SRui Paulo 			elems->vht_capabilities = pos;
542f05cddf9SRui Paulo 			break;
543f05cddf9SRui Paulo 		case WLAN_EID_VHT_OPERATION:
544325151a3SRui Paulo 			if (elen < sizeof(struct ieee80211_vht_operation))
545325151a3SRui Paulo 				break;
546f05cddf9SRui Paulo 			elems->vht_operation = pos;
547f05cddf9SRui Paulo 			break;
548*a90b9d01SCy Schubert 		case WLAN_EID_OPERATING_MODE_NOTIFICATION:
5495b9c547cSRui Paulo 			if (elen != 1)
5505b9c547cSRui Paulo 				break;
551*a90b9d01SCy Schubert 			elems->opmode_notif = pos;
5525b9c547cSRui Paulo 			break;
553f05cddf9SRui Paulo 		case WLAN_EID_LINK_ID:
554f05cddf9SRui Paulo 			if (elen < 18)
555f05cddf9SRui Paulo 				break;
556f05cddf9SRui Paulo 			elems->link_id = pos;
557f05cddf9SRui Paulo 			break;
558f05cddf9SRui Paulo 		case WLAN_EID_INTERWORKING:
559f05cddf9SRui Paulo 			elems->interworking = pos;
560f05cddf9SRui Paulo 			elems->interworking_len = elen;
561f05cddf9SRui Paulo 			break;
5625b9c547cSRui Paulo 		case WLAN_EID_QOS_MAP_SET:
5635b9c547cSRui Paulo 			if (elen < 16)
5645b9c547cSRui Paulo 				break;
5655b9c547cSRui Paulo 			elems->qos_map_set = pos;
5665b9c547cSRui Paulo 			elems->qos_map_set_len = elen;
5675b9c547cSRui Paulo 			break;
568f05cddf9SRui Paulo 		case WLAN_EID_EXT_CAPAB:
569f05cddf9SRui Paulo 			elems->ext_capab = pos;
570f05cddf9SRui Paulo 			elems->ext_capab_len = elen;
571f05cddf9SRui Paulo 			break;
572f05cddf9SRui Paulo 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
573f05cddf9SRui Paulo 			if (elen < 3)
574f05cddf9SRui Paulo 				break;
575f05cddf9SRui Paulo 			elems->bss_max_idle_period = pos;
576f05cddf9SRui Paulo 			break;
577f05cddf9SRui Paulo 		case WLAN_EID_SSID_LIST:
578f05cddf9SRui Paulo 			elems->ssid_list = pos;
579f05cddf9SRui Paulo 			elems->ssid_list_len = elen;
580f05cddf9SRui Paulo 			break;
5815b9c547cSRui Paulo 		case WLAN_EID_AMPE:
5825b9c547cSRui Paulo 			elems->ampe = pos;
5835b9c547cSRui Paulo 			elems->ampe_len = elen;
5845b9c547cSRui Paulo 			break;
5855b9c547cSRui Paulo 		case WLAN_EID_MIC:
5865b9c547cSRui Paulo 			elems->mic = pos;
5875b9c547cSRui Paulo 			elems->mic_len = elen;
5885b9c547cSRui Paulo 			/* after mic everything is encrypted, so stop. */
5894bc52338SCy Schubert 			goto done;
590325151a3SRui Paulo 		case WLAN_EID_MULTI_BAND:
591325151a3SRui Paulo 			if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
592325151a3SRui Paulo 				wpa_printf(MSG_MSGDUMP,
593325151a3SRui Paulo 					   "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
594325151a3SRui Paulo 					   id, elen);
595325151a3SRui Paulo 				break;
596325151a3SRui Paulo 			}
597325151a3SRui Paulo 
598325151a3SRui Paulo 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
599325151a3SRui Paulo 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
600325151a3SRui Paulo 			elems->mb_ies.nof_ies++;
601325151a3SRui Paulo 			break;
602780fb4a2SCy Schubert 		case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
603780fb4a2SCy Schubert 			elems->supp_op_classes = pos;
604780fb4a2SCy Schubert 			elems->supp_op_classes_len = elen;
605780fb4a2SCy Schubert 			break;
606780fb4a2SCy Schubert 		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
607780fb4a2SCy Schubert 			elems->rrm_enabled = pos;
608780fb4a2SCy Schubert 			elems->rrm_enabled_len = elen;
609780fb4a2SCy Schubert 			break;
610*a90b9d01SCy Schubert 		case WLAN_EID_MULTIPLE_BSSID:
611*a90b9d01SCy Schubert 			if (elen < 1)
612*a90b9d01SCy Schubert 				break;
613*a90b9d01SCy Schubert 			elems->mbssid = pos;
614*a90b9d01SCy Schubert 			elems->mbssid_len = elen;
615*a90b9d01SCy Schubert 			break;
61685732ac8SCy Schubert 		case WLAN_EID_CAG_NUMBER:
61785732ac8SCy Schubert 			elems->cag_number = pos;
61885732ac8SCy Schubert 			elems->cag_number_len = elen;
61985732ac8SCy Schubert 			break;
62085732ac8SCy Schubert 		case WLAN_EID_AP_CSN:
62185732ac8SCy Schubert 			if (elen < 1)
62285732ac8SCy Schubert 				break;
62385732ac8SCy Schubert 			elems->ap_csn = pos;
62485732ac8SCy Schubert 			break;
62585732ac8SCy Schubert 		case WLAN_EID_FILS_INDICATION:
62685732ac8SCy Schubert 			if (elen < 2)
62785732ac8SCy Schubert 				break;
62885732ac8SCy Schubert 			elems->fils_indic = pos;
62985732ac8SCy Schubert 			elems->fils_indic_len = elen;
63085732ac8SCy Schubert 			break;
63185732ac8SCy Schubert 		case WLAN_EID_DILS:
63285732ac8SCy Schubert 			if (elen < 2)
63385732ac8SCy Schubert 				break;
63485732ac8SCy Schubert 			elems->dils = pos;
63585732ac8SCy Schubert 			elems->dils_len = elen;
63685732ac8SCy Schubert 			break;
637c1d255d3SCy Schubert 		case WLAN_EID_S1G_CAPABILITIES:
638c1d255d3SCy Schubert 			if (elen < 15)
639c1d255d3SCy Schubert 				break;
640c1d255d3SCy Schubert 			elems->s1g_capab = pos;
641c1d255d3SCy Schubert 			break;
64285732ac8SCy Schubert 		case WLAN_EID_FRAGMENT:
643*a90b9d01SCy Schubert 			wpa_printf(MSG_MSGDUMP,
644*a90b9d01SCy Schubert 				   "Fragment without a valid last element - skip");
645*a90b9d01SCy Schubert 
64685732ac8SCy Schubert 			break;
64785732ac8SCy Schubert 		case WLAN_EID_EXTENSION:
648*a90b9d01SCy Schubert 			if (ieee802_11_parse_extension(pos, elen, elems, start,
649*a90b9d01SCy Schubert 						       len, show_errors))
65085732ac8SCy Schubert 				unknown++;
65185732ac8SCy Schubert 			break;
65239beb93cSSam Leffler 		default:
65339beb93cSSam Leffler 			unknown++;
65439beb93cSSam Leffler 			if (!show_errors)
65539beb93cSSam Leffler 				break;
65639beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
65739beb93cSSam Leffler 				   "ignored unknown element (id=%d elen=%d)",
65839beb93cSSam Leffler 				   id, elen);
65939beb93cSSam Leffler 			break;
66039beb93cSSam Leffler 		}
661c1d255d3SCy Schubert 
662*a90b9d01SCy Schubert 		if (elen == 255 && total_len)
663*a90b9d01SCy Schubert 			*total_len += ieee802_11_fragments_length(
664*a90b9d01SCy Schubert 				elems, pos + elen,
665*a90b9d01SCy Schubert 				(start + len) - (pos + elen));
666c1d255d3SCy Schubert 
66739beb93cSSam Leffler 	}
66839beb93cSSam Leffler 
6694bc52338SCy Schubert 	if (!for_each_element_completed(elem, start, len)) {
6704bc52338SCy Schubert 		if (show_errors) {
6714bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
6724bc52338SCy Schubert 				   "IEEE 802.11 element parse failed @%d",
6734bc52338SCy Schubert 				   (int) (start + len - (const u8 *) elem));
6744bc52338SCy Schubert 			wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
6754bc52338SCy Schubert 		}
67639beb93cSSam Leffler 		return ParseFailed;
6774bc52338SCy Schubert 	}
67839beb93cSSam Leffler 
6794bc52338SCy Schubert done:
68039beb93cSSam Leffler 	return unknown ? ParseUnknown : ParseOK;
68139beb93cSSam Leffler }
682e28a4053SRui Paulo 
683e28a4053SRui Paulo 
684*a90b9d01SCy Schubert /**
685*a90b9d01SCy Schubert  * ieee802_11_parse_elems - Parse information elements in management frames
686*a90b9d01SCy Schubert  * @start: Pointer to the start of IEs
687*a90b9d01SCy Schubert  * @len: Length of IE buffer in octets
688*a90b9d01SCy Schubert  * @elems: Data structure for parsed elements
689*a90b9d01SCy Schubert  * @show_errors: Whether to show parsing errors in debug log
690*a90b9d01SCy Schubert  * Returns: Parsing result
691*a90b9d01SCy Schubert  */
ieee802_11_parse_elems(const u8 * start,size_t len,struct ieee802_11_elems * elems,int show_errors)692*a90b9d01SCy Schubert ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
693*a90b9d01SCy Schubert 				struct ieee802_11_elems *elems,
694*a90b9d01SCy Schubert 				int show_errors)
695*a90b9d01SCy Schubert {
696*a90b9d01SCy Schubert 	os_memset(elems, 0, sizeof(*elems));
697*a90b9d01SCy Schubert 
698*a90b9d01SCy Schubert 	return __ieee802_11_parse_elems(start, len, elems, show_errors);
699*a90b9d01SCy Schubert }
700*a90b9d01SCy Schubert 
701*a90b9d01SCy Schubert 
702*a90b9d01SCy Schubert /**
703*a90b9d01SCy Schubert  * ieee802_11_elems_clear_ids - Clear the data for the given element IDs
704*a90b9d01SCy Schubert  * @ids: Array of element IDs for which data should be cleared.
705*a90b9d01SCy Schubert  * @num: The number of entries in the array
706*a90b9d01SCy Schubert  */
ieee802_11_elems_clear_ids(struct ieee802_11_elems * elems,const u8 * ids,size_t num)707*a90b9d01SCy Schubert void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
708*a90b9d01SCy Schubert 				const u8 *ids, size_t num)
709*a90b9d01SCy Schubert {
710*a90b9d01SCy Schubert 	size_t i;
711*a90b9d01SCy Schubert 
712*a90b9d01SCy Schubert 	for (i = 0; i < num; i++) {
713*a90b9d01SCy Schubert 		switch (ids[i]) {
714*a90b9d01SCy Schubert 		case WLAN_EID_SSID:
715*a90b9d01SCy Schubert 			elems->ssid = NULL;
716*a90b9d01SCy Schubert 			elems->ssid_len = 0;
717*a90b9d01SCy Schubert 			break;
718*a90b9d01SCy Schubert 		case WLAN_EID_SUPP_RATES:
719*a90b9d01SCy Schubert 			elems->supp_rates = NULL;
720*a90b9d01SCy Schubert 			elems->supp_rates_len = 0;
721*a90b9d01SCy Schubert 			break;
722*a90b9d01SCy Schubert 		case WLAN_EID_DS_PARAMS:
723*a90b9d01SCy Schubert 			elems->ds_params = NULL;
724*a90b9d01SCy Schubert 			break;
725*a90b9d01SCy Schubert 		case WLAN_EID_CHALLENGE:
726*a90b9d01SCy Schubert 			elems->challenge = NULL;
727*a90b9d01SCy Schubert 			elems->challenge_len = 0;
728*a90b9d01SCy Schubert 			break;
729*a90b9d01SCy Schubert 		case WLAN_EID_ERP_INFO:
730*a90b9d01SCy Schubert 			elems->erp_info = NULL;
731*a90b9d01SCy Schubert 			break;
732*a90b9d01SCy Schubert 		case WLAN_EID_EXT_SUPP_RATES:
733*a90b9d01SCy Schubert 			elems->ext_supp_rates = NULL;
734*a90b9d01SCy Schubert 			elems->ext_supp_rates_len = 0;
735*a90b9d01SCy Schubert 			break;
736*a90b9d01SCy Schubert 		case WLAN_EID_RSN:
737*a90b9d01SCy Schubert 			elems->rsn_ie = NULL;
738*a90b9d01SCy Schubert 			elems->rsn_ie_len = 0;
739*a90b9d01SCy Schubert 			break;
740*a90b9d01SCy Schubert 		case WLAN_EID_RSNX:
741*a90b9d01SCy Schubert 			elems->rsnxe = NULL;
742*a90b9d01SCy Schubert 			elems->rsnxe_len = 0;
743*a90b9d01SCy Schubert 			break;
744*a90b9d01SCy Schubert 		case WLAN_EID_PWR_CAPABILITY:
745*a90b9d01SCy Schubert 			elems->power_capab = NULL;
746*a90b9d01SCy Schubert 			elems->power_capab_len = 0;
747*a90b9d01SCy Schubert 			break;
748*a90b9d01SCy Schubert 		case WLAN_EID_SUPPORTED_CHANNELS:
749*a90b9d01SCy Schubert 			elems->supp_channels = NULL;
750*a90b9d01SCy Schubert 			elems->supp_channels_len = 0;
751*a90b9d01SCy Schubert 			break;
752*a90b9d01SCy Schubert 		case WLAN_EID_MOBILITY_DOMAIN:
753*a90b9d01SCy Schubert 			elems->mdie = NULL;
754*a90b9d01SCy Schubert 			elems->mdie_len = 0;
755*a90b9d01SCy Schubert 			break;
756*a90b9d01SCy Schubert 		case WLAN_EID_FAST_BSS_TRANSITION:
757*a90b9d01SCy Schubert 			elems->ftie = NULL;
758*a90b9d01SCy Schubert 			elems->ftie_len = 0;
759*a90b9d01SCy Schubert 			break;
760*a90b9d01SCy Schubert 		case WLAN_EID_TIMEOUT_INTERVAL:
761*a90b9d01SCy Schubert 			elems->timeout_int = NULL;
762*a90b9d01SCy Schubert 			break;
763*a90b9d01SCy Schubert 		case WLAN_EID_HT_CAP:
764*a90b9d01SCy Schubert 			elems->ht_capabilities = NULL;
765*a90b9d01SCy Schubert 			break;
766*a90b9d01SCy Schubert 		case WLAN_EID_HT_OPERATION:
767*a90b9d01SCy Schubert 			elems->ht_operation = NULL;
768*a90b9d01SCy Schubert 			break;
769*a90b9d01SCy Schubert 		case WLAN_EID_MESH_CONFIG:
770*a90b9d01SCy Schubert 			elems->mesh_config = NULL;
771*a90b9d01SCy Schubert 			elems->mesh_config_len = 0;
772*a90b9d01SCy Schubert 			break;
773*a90b9d01SCy Schubert 		case WLAN_EID_MESH_ID:
774*a90b9d01SCy Schubert 			elems->mesh_id = NULL;
775*a90b9d01SCy Schubert 			elems->mesh_id_len = 0;
776*a90b9d01SCy Schubert 			break;
777*a90b9d01SCy Schubert 		case WLAN_EID_PEER_MGMT:
778*a90b9d01SCy Schubert 			elems->peer_mgmt = NULL;
779*a90b9d01SCy Schubert 			elems->peer_mgmt_len = 0;
780*a90b9d01SCy Schubert 			break;
781*a90b9d01SCy Schubert 		case WLAN_EID_VHT_CAP:
782*a90b9d01SCy Schubert 			elems->vht_capabilities = NULL;
783*a90b9d01SCy Schubert 			break;
784*a90b9d01SCy Schubert 		case WLAN_EID_VHT_OPERATION:
785*a90b9d01SCy Schubert 			elems->vht_operation = NULL;
786*a90b9d01SCy Schubert 			break;
787*a90b9d01SCy Schubert 		case WLAN_EID_OPERATING_MODE_NOTIFICATION:
788*a90b9d01SCy Schubert 			elems->opmode_notif = NULL;
789*a90b9d01SCy Schubert 			break;
790*a90b9d01SCy Schubert 		case WLAN_EID_LINK_ID:
791*a90b9d01SCy Schubert 			elems->link_id = NULL;
792*a90b9d01SCy Schubert 			break;
793*a90b9d01SCy Schubert 		case WLAN_EID_INTERWORKING:
794*a90b9d01SCy Schubert 			elems->interworking = NULL;
795*a90b9d01SCy Schubert 			elems->interworking_len = 0;
796*a90b9d01SCy Schubert 			break;
797*a90b9d01SCy Schubert 		case WLAN_EID_QOS_MAP_SET:
798*a90b9d01SCy Schubert 			elems->qos_map_set = NULL;
799*a90b9d01SCy Schubert 			elems->qos_map_set_len = 0;
800*a90b9d01SCy Schubert 			break;
801*a90b9d01SCy Schubert 		case WLAN_EID_EXT_CAPAB:
802*a90b9d01SCy Schubert 			elems->ext_capab = NULL;
803*a90b9d01SCy Schubert 			elems->ext_capab_len = 0;
804*a90b9d01SCy Schubert 			break;
805*a90b9d01SCy Schubert 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
806*a90b9d01SCy Schubert 			elems->bss_max_idle_period = NULL;
807*a90b9d01SCy Schubert 			break;
808*a90b9d01SCy Schubert 		case WLAN_EID_SSID_LIST:
809*a90b9d01SCy Schubert 			elems->ssid_list = NULL;
810*a90b9d01SCy Schubert 			elems->ssid_list_len = 0;
811*a90b9d01SCy Schubert 			break;
812*a90b9d01SCy Schubert 		case WLAN_EID_AMPE:
813*a90b9d01SCy Schubert 			elems->ampe = NULL;
814*a90b9d01SCy Schubert 			elems->ampe_len = 0;
815*a90b9d01SCy Schubert 			break;
816*a90b9d01SCy Schubert 		case WLAN_EID_MIC:
817*a90b9d01SCy Schubert 			elems->mic = NULL;
818*a90b9d01SCy Schubert 			elems->mic_len = 0;
819*a90b9d01SCy Schubert 			break;
820*a90b9d01SCy Schubert 		case WLAN_EID_MULTI_BAND:
821*a90b9d01SCy Schubert 			os_memset(&elems->mb_ies, 0, sizeof(elems->mb_ies));
822*a90b9d01SCy Schubert 			elems->mb_ies.nof_ies = 0;
823*a90b9d01SCy Schubert 			break;
824*a90b9d01SCy Schubert 		case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
825*a90b9d01SCy Schubert 			elems->supp_op_classes = NULL;
826*a90b9d01SCy Schubert 			elems->supp_op_classes_len = 0;
827*a90b9d01SCy Schubert 			break;
828*a90b9d01SCy Schubert 		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
829*a90b9d01SCy Schubert 			elems->rrm_enabled = NULL;
830*a90b9d01SCy Schubert 			elems->rrm_enabled_len = 0;
831*a90b9d01SCy Schubert 			break;
832*a90b9d01SCy Schubert 		case WLAN_EID_CAG_NUMBER:
833*a90b9d01SCy Schubert 			elems->cag_number = NULL;
834*a90b9d01SCy Schubert 			elems->cag_number_len = 0;
835*a90b9d01SCy Schubert 			break;
836*a90b9d01SCy Schubert 		case WLAN_EID_AP_CSN:
837*a90b9d01SCy Schubert 			elems->ap_csn = NULL;
838*a90b9d01SCy Schubert 			break;
839*a90b9d01SCy Schubert 		case WLAN_EID_FILS_INDICATION:
840*a90b9d01SCy Schubert 			elems->fils_indic = NULL;
841*a90b9d01SCy Schubert 			elems->fils_indic_len = 0;
842*a90b9d01SCy Schubert 			break;
843*a90b9d01SCy Schubert 		case WLAN_EID_DILS:
844*a90b9d01SCy Schubert 			elems->dils = NULL;
845*a90b9d01SCy Schubert 			elems->dils_len = 0;
846*a90b9d01SCy Schubert 			break;
847*a90b9d01SCy Schubert 		case WLAN_EID_S1G_CAPABILITIES:
848*a90b9d01SCy Schubert 			elems->s1g_capab = NULL;
849*a90b9d01SCy Schubert 			break;
850*a90b9d01SCy Schubert 		}
851*a90b9d01SCy Schubert 	}
852*a90b9d01SCy Schubert }
853*a90b9d01SCy Schubert 
854*a90b9d01SCy Schubert 
855*a90b9d01SCy Schubert /**
856*a90b9d01SCy Schubert  * ieee802_11_elems_clear_ext_ids - Clear the data for the given element
857*a90b9d01SCy Schubert  * extension IDs
858*a90b9d01SCy Schubert  * @ids: Array of element extension IDs for which data should be cleared.
859*a90b9d01SCy Schubert  * @num: The number of entries in the array
860*a90b9d01SCy Schubert  */
ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems * elems,const u8 * ids,size_t num)861*a90b9d01SCy Schubert void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
862*a90b9d01SCy Schubert 				    const u8 *ids, size_t num)
863*a90b9d01SCy Schubert {
864*a90b9d01SCy Schubert 	size_t i;
865*a90b9d01SCy Schubert 
866*a90b9d01SCy Schubert 	for (i = 0; i < num; i++) {
867*a90b9d01SCy Schubert 		switch (ids[i]) {
868*a90b9d01SCy Schubert 		case WLAN_EID_EXT_ASSOC_DELAY_INFO:
869*a90b9d01SCy Schubert 			elems->assoc_delay_info = NULL;
870*a90b9d01SCy Schubert 			break;
871*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_REQ_PARAMS:
872*a90b9d01SCy Schubert 			elems->fils_req_params = NULL;
873*a90b9d01SCy Schubert 			elems->fils_req_params_len = 0;
874*a90b9d01SCy Schubert 			break;
875*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_KEY_CONFIRM:
876*a90b9d01SCy Schubert 			elems->fils_key_confirm = NULL;
877*a90b9d01SCy Schubert 			elems->fils_key_confirm_len = 0;
878*a90b9d01SCy Schubert 			break;
879*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_SESSION:
880*a90b9d01SCy Schubert 			elems->fils_session = NULL;
881*a90b9d01SCy Schubert 			break;
882*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_HLP_CONTAINER:
883*a90b9d01SCy Schubert 			elems->fils_hlp = NULL;
884*a90b9d01SCy Schubert 			elems->fils_hlp_len = 0;
885*a90b9d01SCy Schubert 			break;
886*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
887*a90b9d01SCy Schubert 			elems->fils_ip_addr_assign = NULL;
888*a90b9d01SCy Schubert 			elems->fils_ip_addr_assign_len = 0;
889*a90b9d01SCy Schubert 			break;
890*a90b9d01SCy Schubert 		case WLAN_EID_EXT_KEY_DELIVERY:
891*a90b9d01SCy Schubert 			elems->key_delivery = NULL;
892*a90b9d01SCy Schubert 			elems->key_delivery_len = 0;
893*a90b9d01SCy Schubert 			break;
894*a90b9d01SCy Schubert 		case WLAN_EID_EXT_WRAPPED_DATA:
895*a90b9d01SCy Schubert 			elems->wrapped_data = NULL;
896*a90b9d01SCy Schubert 			elems->wrapped_data_len = 0;
897*a90b9d01SCy Schubert 			break;
898*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_PUBLIC_KEY:
899*a90b9d01SCy Schubert 			elems->fils_pk = NULL;
900*a90b9d01SCy Schubert 			elems->fils_pk_len = 0;
901*a90b9d01SCy Schubert 			break;
902*a90b9d01SCy Schubert 		case WLAN_EID_EXT_FILS_NONCE:
903*a90b9d01SCy Schubert 			elems->fils_nonce = NULL;
904*a90b9d01SCy Schubert 			break;
905*a90b9d01SCy Schubert 		case WLAN_EID_EXT_OWE_DH_PARAM:
906*a90b9d01SCy Schubert 			elems->owe_dh = NULL;
907*a90b9d01SCy Schubert 			elems->owe_dh_len = 0;
908*a90b9d01SCy Schubert 			break;
909*a90b9d01SCy Schubert 		case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
910*a90b9d01SCy Schubert 			elems->password_id = NULL;
911*a90b9d01SCy Schubert 			elems->password_id_len = 0;
912*a90b9d01SCy Schubert 			break;
913*a90b9d01SCy Schubert 		case WLAN_EID_EXT_HE_CAPABILITIES:
914*a90b9d01SCy Schubert 			elems->he_capabilities = NULL;
915*a90b9d01SCy Schubert 			elems->he_capabilities_len = 0;
916*a90b9d01SCy Schubert 			break;
917*a90b9d01SCy Schubert 		case WLAN_EID_EXT_HE_OPERATION:
918*a90b9d01SCy Schubert 			elems->he_operation = NULL;
919*a90b9d01SCy Schubert 			elems->he_operation_len = 0;
920*a90b9d01SCy Schubert 			break;
921*a90b9d01SCy Schubert 		case WLAN_EID_EXT_OCV_OCI:
922*a90b9d01SCy Schubert 			elems->oci = NULL;
923*a90b9d01SCy Schubert 			elems->oci_len = 0;
924*a90b9d01SCy Schubert 			break;
925*a90b9d01SCy Schubert 		case WLAN_EID_EXT_SHORT_SSID_LIST:
926*a90b9d01SCy Schubert 			elems->short_ssid_list = NULL;
927*a90b9d01SCy Schubert 			elems->short_ssid_list_len = 0;
928*a90b9d01SCy Schubert 			break;
929*a90b9d01SCy Schubert 		case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
930*a90b9d01SCy Schubert 			elems->he_6ghz_band_cap = NULL;
931*a90b9d01SCy Schubert 			break;
932*a90b9d01SCy Schubert 		case WLAN_EID_EXT_PASN_PARAMS:
933*a90b9d01SCy Schubert 			elems->pasn_params = NULL;
934*a90b9d01SCy Schubert 			elems->pasn_params_len = 0;
935*a90b9d01SCy Schubert 			break;
936*a90b9d01SCy Schubert 		case WLAN_EID_EXT_MULTI_LINK:
937*a90b9d01SCy Schubert 			elems->basic_mle = NULL;
938*a90b9d01SCy Schubert 			elems->probe_req_mle = NULL;
939*a90b9d01SCy Schubert 			elems->reconf_mle = NULL;
940*a90b9d01SCy Schubert 			elems->tdls_mle = NULL;
941*a90b9d01SCy Schubert 			elems->prior_access_mle = NULL;
942*a90b9d01SCy Schubert 
943*a90b9d01SCy Schubert 			elems->basic_mle_len = 0;
944*a90b9d01SCy Schubert 			elems->probe_req_mle_len = 0;
945*a90b9d01SCy Schubert 			elems->reconf_mle_len = 0;
946*a90b9d01SCy Schubert 			elems->tdls_mle_len = 0;
947*a90b9d01SCy Schubert 			elems->prior_access_mle_len = 0;
948*a90b9d01SCy Schubert 			break;
949*a90b9d01SCy Schubert 		case WLAN_EID_EXT_EHT_CAPABILITIES:
950*a90b9d01SCy Schubert 			elems->eht_capabilities = NULL;
951*a90b9d01SCy Schubert 			elems->eht_capabilities_len = 0;
952*a90b9d01SCy Schubert 			break;
953*a90b9d01SCy Schubert 		case WLAN_EID_EXT_EHT_OPERATION:
954*a90b9d01SCy Schubert 			elems->eht_operation = NULL;
955*a90b9d01SCy Schubert 			elems->eht_operation_len = 0;
956*a90b9d01SCy Schubert 			break;
957*a90b9d01SCy Schubert 		}
958*a90b9d01SCy Schubert 	}
959*a90b9d01SCy Schubert }
960*a90b9d01SCy Schubert 
961*a90b9d01SCy Schubert 
ieee802_11_parse_link_assoc_req(const u8 * start,size_t len,struct ieee802_11_elems * elems,struct wpabuf * mlbuf,u8 link_id,bool show_errors)962*a90b9d01SCy Schubert ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
963*a90b9d01SCy Schubert 					 struct ieee802_11_elems *elems,
964*a90b9d01SCy Schubert 					 struct wpabuf *mlbuf,
965*a90b9d01SCy Schubert 					 u8 link_id, bool show_errors)
966*a90b9d01SCy Schubert {
967*a90b9d01SCy Schubert 	const struct ieee80211_eht_ml *ml;
968*a90b9d01SCy Schubert 	const u8 *pos;
969*a90b9d01SCy Schubert 	ParseRes res = ParseFailed;
970*a90b9d01SCy Schubert 
971*a90b9d01SCy Schubert 	pos = wpabuf_head(mlbuf);
972*a90b9d01SCy Schubert 	len = wpabuf_len(mlbuf);
973*a90b9d01SCy Schubert 
974*a90b9d01SCy Schubert 	/* Must have control and common info length */
975*a90b9d01SCy Schubert 	if (len < sizeof(*ml) + 1 || len < sizeof(*ml) + pos[sizeof(*ml)])
976*a90b9d01SCy Schubert 		goto out;
977*a90b9d01SCy Schubert 
978*a90b9d01SCy Schubert 	ml = (const struct ieee80211_eht_ml *) pos;
979*a90b9d01SCy Schubert 
980*a90b9d01SCy Schubert 	/* As we are interested with the Per-STA profile, ignore other types */
981*a90b9d01SCy Schubert 	if ((le_to_host16(ml->ml_control) & MULTI_LINK_CONTROL_TYPE_MASK) !=
982*a90b9d01SCy Schubert 	     MULTI_LINK_CONTROL_TYPE_BASIC)
983*a90b9d01SCy Schubert 		goto out;
984*a90b9d01SCy Schubert 
985*a90b9d01SCy Schubert 	/* Skip the common info */
986*a90b9d01SCy Schubert 	len -= sizeof(*ml) + pos[sizeof(*ml)];
987*a90b9d01SCy Schubert 	pos += sizeof(*ml) + pos[sizeof(*ml)];
988*a90b9d01SCy Schubert 
989*a90b9d01SCy Schubert 	while (len > 2) {
990*a90b9d01SCy Schubert 		size_t sub_elem_len = *(pos + 1);
991*a90b9d01SCy Schubert 		size_t sta_info_len;
992*a90b9d01SCy Schubert 		u16 link_info_control;
993*a90b9d01SCy Schubert 		const u8 *non_inherit;
994*a90b9d01SCy Schubert 
995*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
996*a90b9d01SCy Schubert 			   "MLD: sub element: len=%zu, sub_elem_len=%zu",
997*a90b9d01SCy Schubert 			   len, sub_elem_len);
998*a90b9d01SCy Schubert 
999*a90b9d01SCy Schubert 		if (2 + sub_elem_len > len) {
1000*a90b9d01SCy Schubert 			if (show_errors)
1001*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1002*a90b9d01SCy Schubert 					   "MLD: error: len=%zu, sub_elem_len=%zu",
1003*a90b9d01SCy Schubert 					   len, sub_elem_len);
1004*a90b9d01SCy Schubert 			goto out;
1005*a90b9d01SCy Schubert 		}
1006*a90b9d01SCy Schubert 
1007*a90b9d01SCy Schubert 		if (*pos != 0) {
1008*a90b9d01SCy Schubert 			pos += 2 + sub_elem_len;
1009*a90b9d01SCy Schubert 			len -= 2 + sub_elem_len;
1010*a90b9d01SCy Schubert 			continue;
1011*a90b9d01SCy Schubert 		}
1012*a90b9d01SCy Schubert 
1013*a90b9d01SCy Schubert 		if (sub_elem_len < 5) {
1014*a90b9d01SCy Schubert 			if (show_errors)
1015*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1016*a90b9d01SCy Schubert 					   "MLD: error: sub_elem_len=%zu < 5",
1017*a90b9d01SCy Schubert 					   sub_elem_len);
1018*a90b9d01SCy Schubert 			goto out;
1019*a90b9d01SCy Schubert 		}
1020*a90b9d01SCy Schubert 
1021*a90b9d01SCy Schubert 		link_info_control = WPA_GET_LE16(pos + 2);
1022*a90b9d01SCy Schubert 		if ((link_info_control & BASIC_MLE_STA_CTRL_LINK_ID_MASK) !=
1023*a90b9d01SCy Schubert 		    link_id) {
1024*a90b9d01SCy Schubert 			pos += 2 + sub_elem_len;
1025*a90b9d01SCy Schubert 			len -= 2 + sub_elem_len;
1026*a90b9d01SCy Schubert 			continue;
1027*a90b9d01SCy Schubert 		}
1028*a90b9d01SCy Schubert 
1029*a90b9d01SCy Schubert 		sta_info_len = *(pos + 4);
1030*a90b9d01SCy Schubert 		if (sub_elem_len < sta_info_len + 3 || sta_info_len < 1) {
1031*a90b9d01SCy Schubert 			if (show_errors)
1032*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1033*a90b9d01SCy Schubert 					   "MLD: error: sub_elem_len=%zu, sta_info_len=%zu",
1034*a90b9d01SCy Schubert 					   sub_elem_len, sta_info_len);
1035*a90b9d01SCy Schubert 			goto out;
1036*a90b9d01SCy Schubert 		}
1037*a90b9d01SCy Schubert 
1038*a90b9d01SCy Schubert 		pos += sta_info_len + 4;
1039*a90b9d01SCy Schubert 		sub_elem_len -= sta_info_len + 2;
1040*a90b9d01SCy Schubert 
1041*a90b9d01SCy Schubert 		if (sub_elem_len < 2) {
1042*a90b9d01SCy Schubert 			if (show_errors)
1043*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1044*a90b9d01SCy Schubert 					   "MLD: missing capability info");
1045*a90b9d01SCy Schubert 			goto out;
1046*a90b9d01SCy Schubert 		}
1047*a90b9d01SCy Schubert 
1048*a90b9d01SCy Schubert 		pos += 2;
1049*a90b9d01SCy Schubert 		sub_elem_len -= 2;
1050*a90b9d01SCy Schubert 
1051*a90b9d01SCy Schubert 		/* Handle non-inheritance */
1052*a90b9d01SCy Schubert 		non_inherit = get_ie_ext(pos, sub_elem_len,
1053*a90b9d01SCy Schubert 					 WLAN_EID_EXT_NON_INHERITANCE);
1054*a90b9d01SCy Schubert 		if (non_inherit && non_inherit[1] > 1) {
1055*a90b9d01SCy Schubert 			u8 non_inherit_len = non_inherit[1] - 1;
1056*a90b9d01SCy Schubert 
1057*a90b9d01SCy Schubert 			/*
1058*a90b9d01SCy Schubert 			 * Do not include the Non-Inheritance element when
1059*a90b9d01SCy Schubert 			 * parsing below. It should be the last element in the
1060*a90b9d01SCy Schubert 			 * subelement.
1061*a90b9d01SCy Schubert 			 */
1062*a90b9d01SCy Schubert 			if (3U + non_inherit_len > sub_elem_len)
1063*a90b9d01SCy Schubert 				goto out;
1064*a90b9d01SCy Schubert 			sub_elem_len -= 3 + non_inherit_len;
1065*a90b9d01SCy Schubert 
1066*a90b9d01SCy Schubert 			/* Skip the ID, length and extension ID */
1067*a90b9d01SCy Schubert 			non_inherit += 3;
1068*a90b9d01SCy Schubert 
1069*a90b9d01SCy Schubert 			if (non_inherit_len < 1UL + non_inherit[0]) {
1070*a90b9d01SCy Schubert 				if (show_errors)
1071*a90b9d01SCy Schubert 					wpa_printf(MSG_DEBUG,
1072*a90b9d01SCy Schubert 						   "MLD: Invalid inheritance");
1073*a90b9d01SCy Schubert 				goto out;
1074*a90b9d01SCy Schubert 			}
1075*a90b9d01SCy Schubert 
1076*a90b9d01SCy Schubert 			ieee802_11_elems_clear_ids(elems, &non_inherit[1],
1077*a90b9d01SCy Schubert 						   non_inherit[0]);
1078*a90b9d01SCy Schubert 
1079*a90b9d01SCy Schubert 			non_inherit_len -= 1 + non_inherit[0];
1080*a90b9d01SCy Schubert 			non_inherit += 1 + non_inherit[0];
1081*a90b9d01SCy Schubert 
1082*a90b9d01SCy Schubert 			if (non_inherit_len < 1UL ||
1083*a90b9d01SCy Schubert 			    non_inherit_len < 1UL + non_inherit[0]) {
1084*a90b9d01SCy Schubert 				if (show_errors)
1085*a90b9d01SCy Schubert 					wpa_printf(MSG_DEBUG,
1086*a90b9d01SCy Schubert 						   "MLD: Invalid inheritance");
1087*a90b9d01SCy Schubert 				goto out;
1088*a90b9d01SCy Schubert 			}
1089*a90b9d01SCy Schubert 
1090*a90b9d01SCy Schubert 			ieee802_11_elems_clear_ext_ids(elems, &non_inherit[1],
1091*a90b9d01SCy Schubert 						       non_inherit[0]);
1092*a90b9d01SCy Schubert 		}
1093*a90b9d01SCy Schubert 
1094*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "MLD: link: sub_elem_len=%zu",
1095*a90b9d01SCy Schubert 			   sub_elem_len);
1096*a90b9d01SCy Schubert 
1097*a90b9d01SCy Schubert 		if (sub_elem_len)
1098*a90b9d01SCy Schubert 			res = __ieee802_11_parse_elems(pos, sub_elem_len,
1099*a90b9d01SCy Schubert 						       elems, show_errors);
1100*a90b9d01SCy Schubert 		else
1101*a90b9d01SCy Schubert 			res = ParseOK;
1102*a90b9d01SCy Schubert 		break;
1103*a90b9d01SCy Schubert 	}
1104*a90b9d01SCy Schubert 
1105*a90b9d01SCy Schubert out:
1106*a90b9d01SCy Schubert 	return res;
1107*a90b9d01SCy Schubert }
1108*a90b9d01SCy Schubert 
1109*a90b9d01SCy Schubert 
ieee802_11_ie_count(const u8 * ies,size_t ies_len)1110e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
1111e28a4053SRui Paulo {
11124bc52338SCy Schubert 	const struct element *elem;
1113e28a4053SRui Paulo 	int count = 0;
1114e28a4053SRui Paulo 
1115e28a4053SRui Paulo 	if (ies == NULL)
1116e28a4053SRui Paulo 		return 0;
1117e28a4053SRui Paulo 
11184bc52338SCy Schubert 	for_each_element(elem, ies, ies_len)
1119e28a4053SRui Paulo 		count++;
1120e28a4053SRui Paulo 
1121e28a4053SRui Paulo 	return count;
1122e28a4053SRui Paulo }
1123e28a4053SRui Paulo 
1124e28a4053SRui Paulo 
ieee802_11_vendor_ie_concat(const u8 * ies,size_t ies_len,u32 oui_type)1125e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
1126e28a4053SRui Paulo 					    u32 oui_type)
1127e28a4053SRui Paulo {
1128e28a4053SRui Paulo 	struct wpabuf *buf;
11294bc52338SCy Schubert 	const struct element *elem, *found = NULL;
1130e28a4053SRui Paulo 
11314bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
11324bc52338SCy Schubert 		if (elem->datalen >= 4 &&
11334bc52338SCy Schubert 		    WPA_GET_BE32(elem->data) == oui_type) {
11344bc52338SCy Schubert 			found = elem;
1135e28a4053SRui Paulo 			break;
1136e28a4053SRui Paulo 		}
1137e28a4053SRui Paulo 	}
1138e28a4053SRui Paulo 
11394bc52338SCy Schubert 	if (!found)
1140e28a4053SRui Paulo 		return NULL; /* No specified vendor IE found */
1141e28a4053SRui Paulo 
1142e28a4053SRui Paulo 	buf = wpabuf_alloc(ies_len);
1143e28a4053SRui Paulo 	if (buf == NULL)
1144e28a4053SRui Paulo 		return NULL;
1145e28a4053SRui Paulo 
1146e28a4053SRui Paulo 	/*
1147e28a4053SRui Paulo 	 * There may be multiple vendor IEs in the message, so need to
1148e28a4053SRui Paulo 	 * concatenate their data fields.
1149e28a4053SRui Paulo 	 */
11504bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
11514bc52338SCy Schubert 		if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
11524bc52338SCy Schubert 			wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
1153e28a4053SRui Paulo 	}
1154e28a4053SRui Paulo 
1155e28a4053SRui Paulo 	return buf;
1156e28a4053SRui Paulo }
1157f05cddf9SRui Paulo 
1158f05cddf9SRui Paulo 
get_hdr_bssid(const struct ieee80211_hdr * hdr,size_t len)1159f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
1160f05cddf9SRui Paulo {
1161f05cddf9SRui Paulo 	u16 fc, type, stype;
1162f05cddf9SRui Paulo 
1163f05cddf9SRui Paulo 	/*
1164f05cddf9SRui Paulo 	 * PS-Poll frames are 16 bytes. All other frames are
1165f05cddf9SRui Paulo 	 * 24 bytes or longer.
1166f05cddf9SRui Paulo 	 */
1167f05cddf9SRui Paulo 	if (len < 16)
1168f05cddf9SRui Paulo 		return NULL;
1169f05cddf9SRui Paulo 
1170f05cddf9SRui Paulo 	fc = le_to_host16(hdr->frame_control);
1171f05cddf9SRui Paulo 	type = WLAN_FC_GET_TYPE(fc);
1172f05cddf9SRui Paulo 	stype = WLAN_FC_GET_STYPE(fc);
1173f05cddf9SRui Paulo 
1174f05cddf9SRui Paulo 	switch (type) {
1175f05cddf9SRui Paulo 	case WLAN_FC_TYPE_DATA:
1176f05cddf9SRui Paulo 		if (len < 24)
1177f05cddf9SRui Paulo 			return NULL;
1178f05cddf9SRui Paulo 		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
1179f05cddf9SRui Paulo 		case WLAN_FC_FROMDS | WLAN_FC_TODS:
1180f05cddf9SRui Paulo 		case WLAN_FC_TODS:
1181f05cddf9SRui Paulo 			return hdr->addr1;
1182f05cddf9SRui Paulo 		case WLAN_FC_FROMDS:
1183f05cddf9SRui Paulo 			return hdr->addr2;
1184f05cddf9SRui Paulo 		default:
1185f05cddf9SRui Paulo 			return NULL;
1186f05cddf9SRui Paulo 		}
1187f05cddf9SRui Paulo 	case WLAN_FC_TYPE_CTRL:
1188f05cddf9SRui Paulo 		if (stype != WLAN_FC_STYPE_PSPOLL)
1189f05cddf9SRui Paulo 			return NULL;
1190f05cddf9SRui Paulo 		return hdr->addr1;
1191f05cddf9SRui Paulo 	case WLAN_FC_TYPE_MGMT:
1192f05cddf9SRui Paulo 		return hdr->addr3;
1193f05cddf9SRui Paulo 	default:
1194f05cddf9SRui Paulo 		return NULL;
1195f05cddf9SRui Paulo 	}
1196f05cddf9SRui Paulo }
1197f05cddf9SRui Paulo 
1198f05cddf9SRui Paulo 
hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],const char * name,const char * val)1199f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
1200f05cddf9SRui Paulo 			  const char *name, const char *val)
1201f05cddf9SRui Paulo {
1202f05cddf9SRui Paulo 	int num, v;
1203f05cddf9SRui Paulo 	const char *pos;
1204f05cddf9SRui Paulo 	struct hostapd_wmm_ac_params *ac;
1205f05cddf9SRui Paulo 
1206f05cddf9SRui Paulo 	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
1207f05cddf9SRui Paulo 	pos = name + 7;
1208f05cddf9SRui Paulo 	if (os_strncmp(pos, "be_", 3) == 0) {
1209f05cddf9SRui Paulo 		num = 0;
1210f05cddf9SRui Paulo 		pos += 3;
1211f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "bk_", 3) == 0) {
1212f05cddf9SRui Paulo 		num = 1;
1213f05cddf9SRui Paulo 		pos += 3;
1214f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "vi_", 3) == 0) {
1215f05cddf9SRui Paulo 		num = 2;
1216f05cddf9SRui Paulo 		pos += 3;
1217f05cddf9SRui Paulo 	} else if (os_strncmp(pos, "vo_", 3) == 0) {
1218f05cddf9SRui Paulo 		num = 3;
1219f05cddf9SRui Paulo 		pos += 3;
1220f05cddf9SRui Paulo 	} else {
1221f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
1222f05cddf9SRui Paulo 		return -1;
1223f05cddf9SRui Paulo 	}
1224f05cddf9SRui Paulo 
1225f05cddf9SRui Paulo 	ac = &wmm_ac_params[num];
1226f05cddf9SRui Paulo 
1227f05cddf9SRui Paulo 	if (os_strcmp(pos, "aifs") == 0) {
1228f05cddf9SRui Paulo 		v = atoi(val);
1229f05cddf9SRui Paulo 		if (v < 1 || v > 255) {
1230f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
1231f05cddf9SRui Paulo 			return -1;
1232f05cddf9SRui Paulo 		}
1233f05cddf9SRui Paulo 		ac->aifs = v;
1234f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "cwmin") == 0) {
1235f05cddf9SRui Paulo 		v = atoi(val);
1236325151a3SRui Paulo 		if (v < 0 || v > 15) {
1237f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
1238f05cddf9SRui Paulo 			return -1;
1239f05cddf9SRui Paulo 		}
1240f05cddf9SRui Paulo 		ac->cwmin = v;
1241f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "cwmax") == 0) {
1242f05cddf9SRui Paulo 		v = atoi(val);
1243325151a3SRui Paulo 		if (v < 0 || v > 15) {
1244f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
1245f05cddf9SRui Paulo 			return -1;
1246f05cddf9SRui Paulo 		}
1247f05cddf9SRui Paulo 		ac->cwmax = v;
1248f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "txop_limit") == 0) {
1249f05cddf9SRui Paulo 		v = atoi(val);
1250f05cddf9SRui Paulo 		if (v < 0 || v > 0xffff) {
1251f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
1252f05cddf9SRui Paulo 			return -1;
1253f05cddf9SRui Paulo 		}
1254f05cddf9SRui Paulo 		ac->txop_limit = v;
1255f05cddf9SRui Paulo 	} else if (os_strcmp(pos, "acm") == 0) {
1256f05cddf9SRui Paulo 		v = atoi(val);
1257f05cddf9SRui Paulo 		if (v < 0 || v > 1) {
1258f05cddf9SRui Paulo 			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
1259f05cddf9SRui Paulo 			return -1;
1260f05cddf9SRui Paulo 		}
1261f05cddf9SRui Paulo 		ac->admission_control_mandatory = v;
1262f05cddf9SRui Paulo 	} else {
1263f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
1264f05cddf9SRui Paulo 		return -1;
1265f05cddf9SRui Paulo 	}
1266f05cddf9SRui Paulo 
1267f05cddf9SRui Paulo 	return 0;
1268f05cddf9SRui Paulo }
12695b9c547cSRui Paulo 
12705b9c547cSRui Paulo 
1271c1d255d3SCy Schubert /* convert floats with one decimal place to value*10 int, i.e.,
1272c1d255d3SCy Schubert  * "1.5" will return 15
1273c1d255d3SCy Schubert  */
hostapd_config_read_int10(const char * value)1274c1d255d3SCy Schubert static int hostapd_config_read_int10(const char *value)
1275c1d255d3SCy Schubert {
1276c1d255d3SCy Schubert 	int i, d;
1277c1d255d3SCy Schubert 	char *pos;
1278c1d255d3SCy Schubert 
1279c1d255d3SCy Schubert 	i = atoi(value);
1280c1d255d3SCy Schubert 	pos = os_strchr(value, '.');
1281c1d255d3SCy Schubert 	d = 0;
1282c1d255d3SCy Schubert 	if (pos) {
1283c1d255d3SCy Schubert 		pos++;
1284c1d255d3SCy Schubert 		if (*pos >= '0' && *pos <= '9')
1285c1d255d3SCy Schubert 			d = *pos - '0';
1286c1d255d3SCy Schubert 	}
1287c1d255d3SCy Schubert 
1288c1d255d3SCy Schubert 	return i * 10 + d;
1289c1d255d3SCy Schubert }
1290c1d255d3SCy Schubert 
1291c1d255d3SCy Schubert 
valid_cw(int cw)1292c1d255d3SCy Schubert static int valid_cw(int cw)
1293c1d255d3SCy Schubert {
1294c1d255d3SCy Schubert 	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
1295c1d255d3SCy Schubert 		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
1296c1d255d3SCy Schubert 		cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
1297c1d255d3SCy Schubert 		cw == 32767);
1298c1d255d3SCy Schubert }
1299c1d255d3SCy Schubert 
1300c1d255d3SCy Schubert 
hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],const char * name,const char * val)1301c1d255d3SCy Schubert int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
1302c1d255d3SCy Schubert 			    const char *name, const char *val)
1303c1d255d3SCy Schubert {
1304c1d255d3SCy Schubert 	int num;
1305c1d255d3SCy Schubert 	const char *pos;
1306c1d255d3SCy Schubert 	struct hostapd_tx_queue_params *queue;
1307c1d255d3SCy Schubert 
1308c1d255d3SCy Schubert 	/* skip 'tx_queue_' prefix */
1309c1d255d3SCy Schubert 	pos = name + 9;
1310c1d255d3SCy Schubert 	if (os_strncmp(pos, "data", 4) == 0 &&
1311c1d255d3SCy Schubert 	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
1312c1d255d3SCy Schubert 		num = pos[4] - '0';
1313c1d255d3SCy Schubert 		pos += 6;
1314c1d255d3SCy Schubert 	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
1315c1d255d3SCy Schubert 		   os_strncmp(pos, "beacon_", 7) == 0) {
1316c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1317c1d255d3SCy Schubert 		return 0;
1318c1d255d3SCy Schubert 	} else {
1319c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
1320c1d255d3SCy Schubert 		return -1;
1321c1d255d3SCy Schubert 	}
1322c1d255d3SCy Schubert 
1323c1d255d3SCy Schubert 	if (num >= NUM_TX_QUEUES) {
1324c1d255d3SCy Schubert 		/* for backwards compatibility, do not trigger failure */
1325c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
1326c1d255d3SCy Schubert 		return 0;
1327c1d255d3SCy Schubert 	}
1328c1d255d3SCy Schubert 
1329c1d255d3SCy Schubert 	queue = &tx_queue[num];
1330c1d255d3SCy Schubert 
1331c1d255d3SCy Schubert 	if (os_strcmp(pos, "aifs") == 0) {
1332c1d255d3SCy Schubert 		queue->aifs = atoi(val);
1333c1d255d3SCy Schubert 		if (queue->aifs < 0 || queue->aifs > 255) {
1334c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
1335c1d255d3SCy Schubert 				   queue->aifs);
1336c1d255d3SCy Schubert 			return -1;
1337c1d255d3SCy Schubert 		}
1338c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "cwmin") == 0) {
1339c1d255d3SCy Schubert 		queue->cwmin = atoi(val);
1340c1d255d3SCy Schubert 		if (!valid_cw(queue->cwmin)) {
1341c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
1342c1d255d3SCy Schubert 				   queue->cwmin);
1343c1d255d3SCy Schubert 			return -1;
1344c1d255d3SCy Schubert 		}
1345c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "cwmax") == 0) {
1346c1d255d3SCy Schubert 		queue->cwmax = atoi(val);
1347c1d255d3SCy Schubert 		if (!valid_cw(queue->cwmax)) {
1348c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
1349c1d255d3SCy Schubert 				   queue->cwmax);
1350c1d255d3SCy Schubert 			return -1;
1351c1d255d3SCy Schubert 		}
1352c1d255d3SCy Schubert 	} else if (os_strcmp(pos, "burst") == 0) {
1353c1d255d3SCy Schubert 		queue->burst = hostapd_config_read_int10(val);
1354c1d255d3SCy Schubert 	} else {
1355c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
1356c1d255d3SCy Schubert 		return -1;
1357c1d255d3SCy Schubert 	}
1358c1d255d3SCy Schubert 
1359c1d255d3SCy Schubert 	return 0;
1360c1d255d3SCy Schubert }
1361c1d255d3SCy Schubert 
1362c1d255d3SCy Schubert 
ieee80211_freq_to_chan(int freq,u8 * channel)13635b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
13645b9c547cSRui Paulo {
1365325151a3SRui Paulo 	u8 op_class;
1366325151a3SRui Paulo 
1367*a90b9d01SCy Schubert 	return ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_USE_HT,
1368780fb4a2SCy Schubert 					     &op_class, channel);
1369325151a3SRui Paulo }
1370325151a3SRui Paulo 
1371325151a3SRui Paulo 
1372325151a3SRui Paulo /**
1373325151a3SRui Paulo  * ieee80211_freq_to_channel_ext - Convert frequency into channel info
1374c1d255d3SCy Schubert  * for HT40, VHT, and HE. DFS channels are not covered.
1375325151a3SRui Paulo  * @freq: Frequency (MHz) to convert
1376325151a3SRui Paulo  * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
1377*a90b9d01SCy Schubert  * @chanwidth: VHT/EDMG/etc. channel width
1378325151a3SRui Paulo  * @op_class: Buffer for returning operating class
1379325151a3SRui Paulo  * @channel: Buffer for returning channel number
1380325151a3SRui Paulo  * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
1381325151a3SRui Paulo  */
1382*a90b9d01SCy Schubert enum hostapd_hw_mode
ieee80211_freq_to_channel_ext(unsigned int freq,int sec_channel,enum oper_chan_width chanwidth,u8 * op_class,u8 * channel)1383*a90b9d01SCy Schubert ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
1384*a90b9d01SCy Schubert 			      enum oper_chan_width chanwidth,
1385325151a3SRui Paulo 			      u8 *op_class, u8 *channel)
1386325151a3SRui Paulo {
1387780fb4a2SCy Schubert 	u8 vht_opclass;
1388780fb4a2SCy Schubert 
1389325151a3SRui Paulo 	/* TODO: more operating classes */
1390325151a3SRui Paulo 
1391325151a3SRui Paulo 	if (sec_channel > 1 || sec_channel < -1)
1392325151a3SRui Paulo 		return NUM_HOSTAPD_MODES;
13935b9c547cSRui Paulo 
13945b9c547cSRui Paulo 	if (freq >= 2412 && freq <= 2472) {
1395325151a3SRui Paulo 		if ((freq - 2407) % 5)
1396325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1397325151a3SRui Paulo 
1398c1d255d3SCy Schubert 		if (chanwidth)
1399325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1400325151a3SRui Paulo 
1401325151a3SRui Paulo 		/* 2.407 GHz, channels 1..13 */
1402325151a3SRui Paulo 		if (sec_channel == 1)
1403325151a3SRui Paulo 			*op_class = 83;
1404325151a3SRui Paulo 		else if (sec_channel == -1)
1405325151a3SRui Paulo 			*op_class = 84;
1406325151a3SRui Paulo 		else
1407325151a3SRui Paulo 			*op_class = 81;
1408325151a3SRui Paulo 
14095b9c547cSRui Paulo 		*channel = (freq - 2407) / 5;
1410325151a3SRui Paulo 
1411325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211G;
1412325151a3SRui Paulo 	}
1413325151a3SRui Paulo 
1414325151a3SRui Paulo 	if (freq == 2484) {
1415c1d255d3SCy Schubert 		if (sec_channel || chanwidth)
1416325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1417325151a3SRui Paulo 
1418325151a3SRui Paulo 		*op_class = 82; /* channel 14 */
14195b9c547cSRui Paulo 		*channel = 14;
1420325151a3SRui Paulo 
1421325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211B;
1422325151a3SRui Paulo 	}
1423325151a3SRui Paulo 
1424325151a3SRui Paulo 	if (freq >= 4900 && freq < 5000) {
1425325151a3SRui Paulo 		if ((freq - 4000) % 5)
1426325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
14275b9c547cSRui Paulo 		*channel = (freq - 4000) / 5;
1428325151a3SRui Paulo 		*op_class = 0; /* TODO */
1429325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1430325151a3SRui Paulo 	}
1431325151a3SRui Paulo 
1432c1d255d3SCy Schubert 	switch (chanwidth) {
1433*a90b9d01SCy Schubert 	case CONF_OPER_CHWIDTH_80MHZ:
1434780fb4a2SCy Schubert 		vht_opclass = 128;
1435780fb4a2SCy Schubert 		break;
1436*a90b9d01SCy Schubert 	case CONF_OPER_CHWIDTH_160MHZ:
1437780fb4a2SCy Schubert 		vht_opclass = 129;
1438780fb4a2SCy Schubert 		break;
1439*a90b9d01SCy Schubert 	case CONF_OPER_CHWIDTH_80P80MHZ:
1440780fb4a2SCy Schubert 		vht_opclass = 130;
1441780fb4a2SCy Schubert 		break;
1442780fb4a2SCy Schubert 	default:
1443780fb4a2SCy Schubert 		vht_opclass = 0;
1444780fb4a2SCy Schubert 		break;
1445780fb4a2SCy Schubert 	}
1446780fb4a2SCy Schubert 
1447325151a3SRui Paulo 	/* 5 GHz, channels 36..48 */
1448325151a3SRui Paulo 	if (freq >= 5180 && freq <= 5240) {
1449325151a3SRui Paulo 		if ((freq - 5000) % 5)
1450325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1451325151a3SRui Paulo 
1452780fb4a2SCy Schubert 		if (vht_opclass)
1453780fb4a2SCy Schubert 			*op_class = vht_opclass;
1454780fb4a2SCy Schubert 		else if (sec_channel == 1)
1455325151a3SRui Paulo 			*op_class = 116;
1456325151a3SRui Paulo 		else if (sec_channel == -1)
1457325151a3SRui Paulo 			*op_class = 117;
1458325151a3SRui Paulo 		else
1459325151a3SRui Paulo 			*op_class = 115;
1460325151a3SRui Paulo 
14615b9c547cSRui Paulo 		*channel = (freq - 5000) / 5;
1462325151a3SRui Paulo 
1463325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1464325151a3SRui Paulo 	}
1465325151a3SRui Paulo 
146685732ac8SCy Schubert 	/* 5 GHz, channels 52..64 */
146785732ac8SCy Schubert 	if (freq >= 5260 && freq <= 5320) {
146885732ac8SCy Schubert 		if ((freq - 5000) % 5)
146985732ac8SCy Schubert 			return NUM_HOSTAPD_MODES;
147085732ac8SCy Schubert 
147185732ac8SCy Schubert 		if (vht_opclass)
147285732ac8SCy Schubert 			*op_class = vht_opclass;
147385732ac8SCy Schubert 		else if (sec_channel == 1)
147485732ac8SCy Schubert 			*op_class = 119;
147585732ac8SCy Schubert 		else if (sec_channel == -1)
147685732ac8SCy Schubert 			*op_class = 120;
147785732ac8SCy Schubert 		else
147885732ac8SCy Schubert 			*op_class = 118;
147985732ac8SCy Schubert 
148085732ac8SCy Schubert 		*channel = (freq - 5000) / 5;
148185732ac8SCy Schubert 
148285732ac8SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
148385732ac8SCy Schubert 	}
148485732ac8SCy Schubert 
1485c1d255d3SCy Schubert 	/* 5 GHz, channels 149..177 */
1486c1d255d3SCy Schubert 	if (freq >= 5745 && freq <= 5885) {
1487325151a3SRui Paulo 		if ((freq - 5000) % 5)
1488325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1489325151a3SRui Paulo 
1490780fb4a2SCy Schubert 		if (vht_opclass)
1491780fb4a2SCy Schubert 			*op_class = vht_opclass;
1492780fb4a2SCy Schubert 		else if (sec_channel == 1)
1493780fb4a2SCy Schubert 			*op_class = 126;
1494780fb4a2SCy Schubert 		else if (sec_channel == -1)
1495780fb4a2SCy Schubert 			*op_class = 127;
1496780fb4a2SCy Schubert 		else
1497325151a3SRui Paulo 			*op_class = 125;
1498325151a3SRui Paulo 
1499325151a3SRui Paulo 		*channel = (freq - 5000) / 5;
1500325151a3SRui Paulo 
1501325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1502325151a3SRui Paulo 	}
1503325151a3SRui Paulo 
15044b72b91aSCy Schubert 	/* 5 GHz, channels 100..144 */
15054b72b91aSCy Schubert 	if (freq >= 5500 && freq <= 5720) {
1506780fb4a2SCy Schubert 		if ((freq - 5000) % 5)
1507780fb4a2SCy Schubert 			return NUM_HOSTAPD_MODES;
1508780fb4a2SCy Schubert 
1509780fb4a2SCy Schubert 		if (vht_opclass)
1510780fb4a2SCy Schubert 			*op_class = vht_opclass;
1511780fb4a2SCy Schubert 		else if (sec_channel == 1)
1512780fb4a2SCy Schubert 			*op_class = 122;
1513780fb4a2SCy Schubert 		else if (sec_channel == -1)
1514780fb4a2SCy Schubert 			*op_class = 123;
1515780fb4a2SCy Schubert 		else
1516780fb4a2SCy Schubert 			*op_class = 121;
1517780fb4a2SCy Schubert 
1518780fb4a2SCy Schubert 		*channel = (freq - 5000) / 5;
1519780fb4a2SCy Schubert 
1520780fb4a2SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1521780fb4a2SCy Schubert 	}
1522780fb4a2SCy Schubert 
1523325151a3SRui Paulo 	if (freq >= 5000 && freq < 5900) {
1524325151a3SRui Paulo 		if ((freq - 5000) % 5)
1525325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1526325151a3SRui Paulo 		*channel = (freq - 5000) / 5;
1527325151a3SRui Paulo 		*op_class = 0; /* TODO */
1528325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211A;
1529325151a3SRui Paulo 	}
1530325151a3SRui Paulo 
1531c1d255d3SCy Schubert 	if (freq > 5950 && freq <= 7115) {
1532c1d255d3SCy Schubert 		if ((freq - 5950) % 5)
1533325151a3SRui Paulo 			return NUM_HOSTAPD_MODES;
1534325151a3SRui Paulo 
1535c1d255d3SCy Schubert 		switch (chanwidth) {
1536*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_80MHZ:
1537c1d255d3SCy Schubert 			*op_class = 133;
1538c1d255d3SCy Schubert 			break;
1539*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_160MHZ:
1540c1d255d3SCy Schubert 			*op_class = 134;
1541c1d255d3SCy Schubert 			break;
1542*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_80P80MHZ:
1543c1d255d3SCy Schubert 			*op_class = 135;
1544c1d255d3SCy Schubert 			break;
1545*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_320MHZ:
1546*a90b9d01SCy Schubert 			*op_class = 137;
1547*a90b9d01SCy Schubert 			break;
1548c1d255d3SCy Schubert 		default:
1549c1d255d3SCy Schubert 			if (sec_channel)
1550c1d255d3SCy Schubert 				*op_class = 132;
1551c1d255d3SCy Schubert 			else
1552c1d255d3SCy Schubert 				*op_class = 131;
1553c1d255d3SCy Schubert 			break;
1554c1d255d3SCy Schubert 		}
1555c1d255d3SCy Schubert 
1556c1d255d3SCy Schubert 		*channel = (freq - 5950) / 5;
1557c1d255d3SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1558c1d255d3SCy Schubert 	}
1559c1d255d3SCy Schubert 
1560c1d255d3SCy Schubert 	if (freq == 5935) {
1561c1d255d3SCy Schubert 		*op_class = 136;
1562c1d255d3SCy Schubert 		*channel = (freq - 5925) / 5;
1563c1d255d3SCy Schubert 		return HOSTAPD_MODE_IEEE80211A;
1564c1d255d3SCy Schubert 	}
1565c1d255d3SCy Schubert 
1566c1d255d3SCy Schubert 	/* 56.16 GHz, channel 1..6 */
1567c1d255d3SCy Schubert 	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
1568c1d255d3SCy Schubert 		if (sec_channel)
1569c1d255d3SCy Schubert 			return NUM_HOSTAPD_MODES;
1570c1d255d3SCy Schubert 
1571c1d255d3SCy Schubert 		switch (chanwidth) {
1572*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_USE_HT:
1573*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_2160MHZ:
15745b9c547cSRui Paulo 			*channel = (freq - 56160) / 2160;
1575325151a3SRui Paulo 			*op_class = 180;
1576c1d255d3SCy Schubert 			break;
1577*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_4320MHZ:
1578c1d255d3SCy Schubert 			/* EDMG channels 9 - 13 */
1579c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 5)
1580c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1581c1d255d3SCy Schubert 
1582c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 8;
1583c1d255d3SCy Schubert 			*op_class = 181;
1584c1d255d3SCy Schubert 			break;
1585*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_6480MHZ:
1586c1d255d3SCy Schubert 			/* EDMG channels 17 - 20 */
1587c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 4)
1588c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1589c1d255d3SCy Schubert 
1590c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 16;
1591c1d255d3SCy Schubert 			*op_class = 182;
1592c1d255d3SCy Schubert 			break;
1593*a90b9d01SCy Schubert 		case CONF_OPER_CHWIDTH_8640MHZ:
1594c1d255d3SCy Schubert 			/* EDMG channels 25 - 27 */
1595c1d255d3SCy Schubert 			if (freq > 56160 + 2160 * 3)
1596c1d255d3SCy Schubert 				return NUM_HOSTAPD_MODES;
1597c1d255d3SCy Schubert 
1598c1d255d3SCy Schubert 			*channel = (freq - 56160) / 2160 + 24;
1599c1d255d3SCy Schubert 			*op_class = 183;
1600c1d255d3SCy Schubert 			break;
1601c1d255d3SCy Schubert 		default:
1602c1d255d3SCy Schubert 			return NUM_HOSTAPD_MODES;
1603c1d255d3SCy Schubert 		}
1604325151a3SRui Paulo 
1605325151a3SRui Paulo 		return HOSTAPD_MODE_IEEE80211AD;
16065b9c547cSRui Paulo 	}
16075b9c547cSRui Paulo 
1608325151a3SRui Paulo 	return NUM_HOSTAPD_MODES;
16095b9c547cSRui Paulo }
16105b9c547cSRui Paulo 
16115b9c547cSRui Paulo 
ieee80211_chaninfo_to_channel(unsigned int freq,enum chan_width chanwidth,int sec_channel,u8 * op_class,u8 * channel)16124bc52338SCy Schubert int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
16134bc52338SCy Schubert 				  int sec_channel, u8 *op_class, u8 *channel)
16144bc52338SCy Schubert {
1615c1d255d3SCy Schubert 	int cw = CHAN_WIDTH_UNKNOWN;
16164bc52338SCy Schubert 
16174bc52338SCy Schubert 	switch (chanwidth) {
16184bc52338SCy Schubert 	case CHAN_WIDTH_UNKNOWN:
16194bc52338SCy Schubert 	case CHAN_WIDTH_20_NOHT:
16204bc52338SCy Schubert 	case CHAN_WIDTH_20:
16214bc52338SCy Schubert 	case CHAN_WIDTH_40:
1622*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_USE_HT;
16234bc52338SCy Schubert 		break;
16244bc52338SCy Schubert 	case CHAN_WIDTH_80:
1625*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_80MHZ;
16264bc52338SCy Schubert 		break;
16274bc52338SCy Schubert 	case CHAN_WIDTH_80P80:
1628*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_80P80MHZ;
16294bc52338SCy Schubert 		break;
16304bc52338SCy Schubert 	case CHAN_WIDTH_160:
1631*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_160MHZ;
1632c1d255d3SCy Schubert 		break;
1633c1d255d3SCy Schubert 	case CHAN_WIDTH_2160:
1634*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_2160MHZ;
1635c1d255d3SCy Schubert 		break;
1636c1d255d3SCy Schubert 	case CHAN_WIDTH_4320:
1637*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_4320MHZ;
1638c1d255d3SCy Schubert 		break;
1639c1d255d3SCy Schubert 	case CHAN_WIDTH_6480:
1640*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_6480MHZ;
1641c1d255d3SCy Schubert 		break;
1642c1d255d3SCy Schubert 	case CHAN_WIDTH_8640:
1643*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_8640MHZ;
1644*a90b9d01SCy Schubert 		break;
1645*a90b9d01SCy Schubert 	case CHAN_WIDTH_320:
1646*a90b9d01SCy Schubert 		cw = CONF_OPER_CHWIDTH_320MHZ;
16474bc52338SCy Schubert 		break;
16484bc52338SCy Schubert 	}
16494bc52338SCy Schubert 
1650c1d255d3SCy Schubert 	if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
16514bc52338SCy Schubert 					  channel) == NUM_HOSTAPD_MODES) {
16524bc52338SCy Schubert 		wpa_printf(MSG_WARNING,
16534bc52338SCy Schubert 			   "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
16544bc52338SCy Schubert 			   freq, chanwidth, sec_channel);
16554bc52338SCy Schubert 		return -1;
16564bc52338SCy Schubert 	}
16574bc52338SCy Schubert 
16584bc52338SCy Schubert 	return 0;
16594bc52338SCy Schubert }
16604bc52338SCy Schubert 
16614bc52338SCy Schubert 
1662325151a3SRui Paulo static const char *const us_op_class_cc[] = {
16635b9c547cSRui Paulo 	"US", "CA", NULL
16645b9c547cSRui Paulo };
16655b9c547cSRui Paulo 
1666325151a3SRui Paulo static const char *const eu_op_class_cc[] = {
16675b9c547cSRui Paulo 	"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
16685b9c547cSRui Paulo 	"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
16695b9c547cSRui Paulo 	"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
16705b9c547cSRui Paulo 	"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
16715b9c547cSRui Paulo };
16725b9c547cSRui Paulo 
1673325151a3SRui Paulo static const char *const jp_op_class_cc[] = {
16745b9c547cSRui Paulo 	"JP", NULL
16755b9c547cSRui Paulo };
16765b9c547cSRui Paulo 
1677325151a3SRui Paulo static const char *const cn_op_class_cc[] = {
1678325151a3SRui Paulo 	"CN", NULL
16795b9c547cSRui Paulo };
16805b9c547cSRui Paulo 
16815b9c547cSRui Paulo 
country_match(const char * const cc[],const char * const country)1682325151a3SRui Paulo static int country_match(const char *const cc[], const char *const country)
16835b9c547cSRui Paulo {
16845b9c547cSRui Paulo 	int i;
16855b9c547cSRui Paulo 
16865b9c547cSRui Paulo 	if (country == NULL)
16875b9c547cSRui Paulo 		return 0;
16885b9c547cSRui Paulo 	for (i = 0; cc[i]; i++) {
16895b9c547cSRui Paulo 		if (cc[i][0] == country[0] && cc[i][1] == country[1])
16905b9c547cSRui Paulo 			return 1;
16915b9c547cSRui Paulo 	}
16925b9c547cSRui Paulo 
16935b9c547cSRui Paulo 	return 0;
16945b9c547cSRui Paulo }
16955b9c547cSRui Paulo 
16965b9c547cSRui Paulo 
ieee80211_chan_to_freq_us(u8 op_class,u8 chan)16975b9c547cSRui Paulo static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
16985b9c547cSRui Paulo {
16995b9c547cSRui Paulo 	switch (op_class) {
17005b9c547cSRui Paulo 	case 12: /* channels 1..11 */
17015b9c547cSRui Paulo 	case 32: /* channels 1..7; 40 MHz */
17025b9c547cSRui Paulo 	case 33: /* channels 5..11; 40 MHz */
17035b9c547cSRui Paulo 		if (chan < 1 || chan > 11)
17045b9c547cSRui Paulo 			return -1;
17055b9c547cSRui Paulo 		return 2407 + 5 * chan;
17065b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
17075b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
17085b9c547cSRui Paulo 	case 22: /* channels 36,44; 40 MHz */
17095b9c547cSRui Paulo 	case 23: /* channels 52,60; 40 MHz */
17105b9c547cSRui Paulo 	case 27: /* channels 40,48; 40 MHz */
17115b9c547cSRui Paulo 	case 28: /* channels 56,64; 40 MHz */
17125b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
17135b9c547cSRui Paulo 			return -1;
17145b9c547cSRui Paulo 		return 5000 + 5 * chan;
17155b9c547cSRui Paulo 	case 4: /* channels 100-144 */
17165b9c547cSRui Paulo 	case 24: /* channels 100-140; 40 MHz */
17175b9c547cSRui Paulo 		if (chan < 100 || chan > 144)
17185b9c547cSRui Paulo 			return -1;
17195b9c547cSRui Paulo 		return 5000 + 5 * chan;
17205b9c547cSRui Paulo 	case 3: /* channels 149,153,157,161 */
17215b9c547cSRui Paulo 	case 25: /* channels 149,157; 40 MHz */
17225b9c547cSRui Paulo 	case 26: /* channels 149,157; 40 MHz */
17235b9c547cSRui Paulo 	case 30: /* channels 153,161; 40 MHz */
17245b9c547cSRui Paulo 	case 31: /* channels 153,161; 40 MHz */
17255b9c547cSRui Paulo 		if (chan < 149 || chan > 161)
17265b9c547cSRui Paulo 			return -1;
17275b9c547cSRui Paulo 		return 5000 + 5 * chan;
1728325151a3SRui Paulo 	case 5: /* channels 149,153,157,161,165 */
1729325151a3SRui Paulo 		if (chan < 149 || chan > 165)
1730325151a3SRui Paulo 			return -1;
1731325151a3SRui Paulo 		return 5000 + 5 * chan;
1732c1d255d3SCy Schubert 	case 34: /* 60 GHz band, channels 1..8 */
1733c1d255d3SCy Schubert 		if (chan < 1 || chan > 8)
17345b9c547cSRui Paulo 			return -1;
17355b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1736c1d255d3SCy Schubert 	case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
1737c1d255d3SCy Schubert 		if (chan < 9 || chan > 15)
1738c1d255d3SCy Schubert 			return -1;
1739c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1740c1d255d3SCy Schubert 	case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
1741c1d255d3SCy Schubert 		if (chan < 17 || chan > 22)
1742c1d255d3SCy Schubert 			return -1;
1743c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1744c1d255d3SCy Schubert 	case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
1745c1d255d3SCy Schubert 		if (chan < 25 || chan > 29)
1746c1d255d3SCy Schubert 			return -1;
1747c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
1748*a90b9d01SCy Schubert 	default:
17495b9c547cSRui Paulo 		return -1;
17505b9c547cSRui Paulo 	}
1751*a90b9d01SCy Schubert }
17525b9c547cSRui Paulo 
17535b9c547cSRui Paulo 
ieee80211_chan_to_freq_eu(u8 op_class,u8 chan)17545b9c547cSRui Paulo static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
17555b9c547cSRui Paulo {
17565b9c547cSRui Paulo 	switch (op_class) {
17575b9c547cSRui Paulo 	case 4: /* channels 1..13 */
17585b9c547cSRui Paulo 	case 11: /* channels 1..9; 40 MHz */
17595b9c547cSRui Paulo 	case 12: /* channels 5..13; 40 MHz */
17605b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
17615b9c547cSRui Paulo 			return -1;
17625b9c547cSRui Paulo 		return 2407 + 5 * chan;
17635b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
17645b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
17655b9c547cSRui Paulo 	case 5: /* channels 36,44; 40 MHz */
17665b9c547cSRui Paulo 	case 6: /* channels 52,60; 40 MHz */
17675b9c547cSRui Paulo 	case 8: /* channels 40,48; 40 MHz */
17685b9c547cSRui Paulo 	case 9: /* channels 56,64; 40 MHz */
17695b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
17705b9c547cSRui Paulo 			return -1;
17715b9c547cSRui Paulo 		return 5000 + 5 * chan;
17725b9c547cSRui Paulo 	case 3: /* channels 100-140 */
17735b9c547cSRui Paulo 	case 7: /* channels 100-132; 40 MHz */
17745b9c547cSRui Paulo 	case 10: /* channels 104-136; 40 MHz */
17755b9c547cSRui Paulo 	case 16: /* channels 100-140 */
17765b9c547cSRui Paulo 		if (chan < 100 || chan > 140)
17775b9c547cSRui Paulo 			return -1;
17785b9c547cSRui Paulo 		return 5000 + 5 * chan;
17795b9c547cSRui Paulo 	case 17: /* channels 149,153,157,161,165,169 */
17805b9c547cSRui Paulo 		if (chan < 149 || chan > 169)
17815b9c547cSRui Paulo 			return -1;
17825b9c547cSRui Paulo 		return 5000 + 5 * chan;
1783c1d255d3SCy Schubert 	case 18: /* 60 GHz band, channels 1..6 */
1784c1d255d3SCy Schubert 		if (chan < 1 || chan > 6)
17855b9c547cSRui Paulo 			return -1;
17865b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1787c1d255d3SCy Schubert 	case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
1788c1d255d3SCy Schubert 		if (chan < 9 || chan > 11)
1789c1d255d3SCy Schubert 			return -1;
1790c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1791c1d255d3SCy Schubert 	case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
1792c1d255d3SCy Schubert 		if (chan < 17 || chan > 18)
1793c1d255d3SCy Schubert 			return -1;
1794c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1795c1d255d3SCy Schubert 	case 23: /* 60 GHz band, EDMG CB4, channels 25 */
1796c1d255d3SCy Schubert 		if (chan != 25)
1797c1d255d3SCy Schubert 			return -1;
1798c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
1799*a90b9d01SCy Schubert 	default:
18005b9c547cSRui Paulo 		return -1;
18015b9c547cSRui Paulo 	}
1802*a90b9d01SCy Schubert }
18035b9c547cSRui Paulo 
18045b9c547cSRui Paulo 
ieee80211_chan_to_freq_jp(u8 op_class,u8 chan)18055b9c547cSRui Paulo static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
18065b9c547cSRui Paulo {
1807*a90b9d01SCy Schubert 	/* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */
18085b9c547cSRui Paulo 	switch (op_class) {
18095b9c547cSRui Paulo 	case 30: /* channels 1..13 */
18105b9c547cSRui Paulo 	case 56: /* channels 1..9; 40 MHz */
18115b9c547cSRui Paulo 	case 57: /* channels 5..13; 40 MHz */
18125b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
18135b9c547cSRui Paulo 			return -1;
18145b9c547cSRui Paulo 		return 2407 + 5 * chan;
18155b9c547cSRui Paulo 	case 31: /* channel 14 */
18165b9c547cSRui Paulo 		if (chan != 14)
18175b9c547cSRui Paulo 			return -1;
18185b9c547cSRui Paulo 		return 2414 + 5 * chan;
18195b9c547cSRui Paulo 	case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
18205b9c547cSRui Paulo 	case 32: /* channels 52,56,60,64 */
18215b9c547cSRui Paulo 	case 33: /* channels 52,56,60,64 */
18225b9c547cSRui Paulo 	case 36: /* channels 36,44; 40 MHz */
18235b9c547cSRui Paulo 	case 37: /* channels 52,60; 40 MHz */
18245b9c547cSRui Paulo 	case 38: /* channels 52,60; 40 MHz */
18255b9c547cSRui Paulo 	case 41: /* channels 40,48; 40 MHz */
18265b9c547cSRui Paulo 	case 42: /* channels 56,64; 40 MHz */
18275b9c547cSRui Paulo 	case 43: /* channels 56,64; 40 MHz */
18285b9c547cSRui Paulo 		if (chan < 34 || chan > 64)
18295b9c547cSRui Paulo 			return -1;
18305b9c547cSRui Paulo 		return 5000 + 5 * chan;
1831*a90b9d01SCy Schubert 	case 34: /* channels 100-144 */
1832*a90b9d01SCy Schubert 	case 35: /* reserved */
1833*a90b9d01SCy Schubert 	case 39: /* channels 100-140; 40 MHz */
1834*a90b9d01SCy Schubert 	case 40: /* reserved */
1835*a90b9d01SCy Schubert 	case 44: /* channels 104-144; 40 MHz */
1836*a90b9d01SCy Schubert 	case 45: /* reserved */
1837*a90b9d01SCy Schubert 	case 58: /* channels 100-144 */
1838*a90b9d01SCy Schubert 		if (chan < 100 || chan > 144)
18395b9c547cSRui Paulo 			return -1;
18405b9c547cSRui Paulo 		return 5000 + 5 * chan;
1841c1d255d3SCy Schubert 	case 59: /* 60 GHz band, channels 1..6 */
1842c1d255d3SCy Schubert 		if (chan < 1 || chan > 6)
18435b9c547cSRui Paulo 			return -1;
18445b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1845c1d255d3SCy Schubert 	case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
1846c1d255d3SCy Schubert 		if (chan < 9 || chan > 11)
1847c1d255d3SCy Schubert 			return -1;
1848c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1849c1d255d3SCy Schubert 	case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
1850c1d255d3SCy Schubert 		if (chan < 17 || chan > 18)
1851c1d255d3SCy Schubert 			return -1;
1852c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1853c1d255d3SCy Schubert 	case 64: /* 60 GHz band, EDMG CB4, channel 25 */
1854c1d255d3SCy Schubert 		if (chan != 25)
1855c1d255d3SCy Schubert 			return -1;
1856c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
1857*a90b9d01SCy Schubert 	default:
18585b9c547cSRui Paulo 		return -1;
18595b9c547cSRui Paulo 	}
1860*a90b9d01SCy Schubert }
18615b9c547cSRui Paulo 
18625b9c547cSRui Paulo 
ieee80211_chan_to_freq_cn(u8 op_class,u8 chan)18635b9c547cSRui Paulo static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
18645b9c547cSRui Paulo {
18655b9c547cSRui Paulo 	switch (op_class) {
18665b9c547cSRui Paulo 	case 7: /* channels 1..13 */
18675b9c547cSRui Paulo 	case 8: /* channels 1..9; 40 MHz */
18685b9c547cSRui Paulo 	case 9: /* channels 5..13; 40 MHz */
18695b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
18705b9c547cSRui Paulo 			return -1;
18715b9c547cSRui Paulo 		return 2407 + 5 * chan;
18725b9c547cSRui Paulo 	case 1: /* channels 36,40,44,48 */
18735b9c547cSRui Paulo 	case 2: /* channels 52,56,60,64; dfs */
18745b9c547cSRui Paulo 	case 4: /* channels 36,44; 40 MHz */
18755b9c547cSRui Paulo 	case 5: /* channels 52,60; 40 MHz */
18765b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
18775b9c547cSRui Paulo 			return -1;
18785b9c547cSRui Paulo 		return 5000 + 5 * chan;
18795b9c547cSRui Paulo 	case 3: /* channels 149,153,157,161,165 */
18805b9c547cSRui Paulo 	case 6: /* channels 149,157; 40 MHz */
18815b9c547cSRui Paulo 		if (chan < 149 || chan > 165)
18825b9c547cSRui Paulo 			return -1;
18835b9c547cSRui Paulo 		return 5000 + 5 * chan;
1884*a90b9d01SCy Schubert 	default:
18855b9c547cSRui Paulo 		return -1;
18865b9c547cSRui Paulo 	}
1887*a90b9d01SCy Schubert }
18885b9c547cSRui Paulo 
18895b9c547cSRui Paulo 
ieee80211_chan_to_freq_global(u8 op_class,u8 chan)18905b9c547cSRui Paulo static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
18915b9c547cSRui Paulo {
1892*a90b9d01SCy Schubert 	/* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */
18935b9c547cSRui Paulo 	switch (op_class) {
18945b9c547cSRui Paulo 	case 81:
18955b9c547cSRui Paulo 		/* channels 1..13 */
18965b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
18975b9c547cSRui Paulo 			return -1;
18985b9c547cSRui Paulo 		return 2407 + 5 * chan;
18995b9c547cSRui Paulo 	case 82:
19005b9c547cSRui Paulo 		/* channel 14 */
19015b9c547cSRui Paulo 		if (chan != 14)
19025b9c547cSRui Paulo 			return -1;
19035b9c547cSRui Paulo 		return 2414 + 5 * chan;
19045b9c547cSRui Paulo 	case 83: /* channels 1..9; 40 MHz */
19055b9c547cSRui Paulo 	case 84: /* channels 5..13; 40 MHz */
19065b9c547cSRui Paulo 		if (chan < 1 || chan > 13)
19075b9c547cSRui Paulo 			return -1;
19085b9c547cSRui Paulo 		return 2407 + 5 * chan;
19095b9c547cSRui Paulo 	case 115: /* channels 36,40,44,48; indoor only */
19105b9c547cSRui Paulo 	case 116: /* channels 36,44; 40 MHz; indoor only */
19115b9c547cSRui Paulo 	case 117: /* channels 40,48; 40 MHz; indoor only */
19125b9c547cSRui Paulo 	case 118: /* channels 52,56,60,64; dfs */
19135b9c547cSRui Paulo 	case 119: /* channels 52,60; 40 MHz; dfs */
19145b9c547cSRui Paulo 	case 120: /* channels 56,64; 40 MHz; dfs */
19155b9c547cSRui Paulo 		if (chan < 36 || chan > 64)
19165b9c547cSRui Paulo 			return -1;
19175b9c547cSRui Paulo 		return 5000 + 5 * chan;
1918*a90b9d01SCy Schubert 	case 121: /* channels 100-144 */
1919*a90b9d01SCy Schubert 	case 122: /* channels 100-140; 40 MHz */
1920*a90b9d01SCy Schubert 	case 123: /* channels 104-144; 40 MHz */
1921*a90b9d01SCy Schubert 		if (chan < 100 || chan > 144)
19225b9c547cSRui Paulo 			return -1;
19235b9c547cSRui Paulo 		return 5000 + 5 * chan;
19245b9c547cSRui Paulo 	case 124: /* channels 149,153,157,161 */
19255b9c547cSRui Paulo 		if (chan < 149 || chan > 161)
19265b9c547cSRui Paulo 			return -1;
19275b9c547cSRui Paulo 		return 5000 + 5 * chan;
1928c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,173,177 */
1929c1d255d3SCy Schubert 	case 126: /* channels 149,157,165,173; 40 MHz */
1930c1d255d3SCy Schubert 	case 127: /* channels 153,161,169,177; 40 MHz */
1931c1d255d3SCy Schubert 		if (chan < 149 || chan > 177)
1932325151a3SRui Paulo 			return -1;
1933325151a3SRui Paulo 		return 5000 + 5 * chan;
1934c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
1935c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
1936c1d255d3SCy Schubert 		if (chan < 36 || chan > 177)
19375b9c547cSRui Paulo 			return -1;
19385b9c547cSRui Paulo 		return 5000 + 5 * chan;
1939c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
1940c1d255d3SCy Schubert 		if (chan < 36 || chan > 177)
19415b9c547cSRui Paulo 			return -1;
19425b9c547cSRui Paulo 		return 5000 + 5 * chan;
1943c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
1944c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
1945c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
1946c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
1947c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
1948*a90b9d01SCy Schubert 	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
1949c1d255d3SCy Schubert 		if (chan < 1 || chan > 233)
1950c1d255d3SCy Schubert 			return -1;
1951c1d255d3SCy Schubert 		return 5950 + chan * 5;
1952c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
1953c1d255d3SCy Schubert 		if (chan == 2)
1954c1d255d3SCy Schubert 			return 5935;
1955c1d255d3SCy Schubert 		return -1;
1956c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
1957c1d255d3SCy Schubert 		if (chan < 1 || chan > 8)
19585b9c547cSRui Paulo 			return -1;
19595b9c547cSRui Paulo 		return 56160 + 2160 * chan;
1960c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
1961c1d255d3SCy Schubert 		if (chan < 9 || chan > 15)
1962c1d255d3SCy Schubert 			return -1;
1963c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 8);
1964c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
1965c1d255d3SCy Schubert 		if (chan < 17 || chan > 22)
1966c1d255d3SCy Schubert 			return -1;
1967c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 16);
1968c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
1969c1d255d3SCy Schubert 		if (chan < 25 || chan > 29)
1970c1d255d3SCy Schubert 			return -1;
1971c1d255d3SCy Schubert 		return 56160 + 2160 * (chan - 24);
1972*a90b9d01SCy Schubert 	default:
19735b9c547cSRui Paulo 		return -1;
19745b9c547cSRui Paulo 	}
1975*a90b9d01SCy Schubert }
19765b9c547cSRui Paulo 
19775b9c547cSRui Paulo /**
19785b9c547cSRui Paulo  * ieee80211_chan_to_freq - Convert channel info to frequency
19795b9c547cSRui Paulo  * @country: Country code, if known; otherwise, global operating class is used
19805b9c547cSRui Paulo  * @op_class: Operating class
19815b9c547cSRui Paulo  * @chan: Channel number
19825b9c547cSRui Paulo  * Returns: Frequency in MHz or -1 if the specified channel is unknown
19835b9c547cSRui Paulo  */
ieee80211_chan_to_freq(const char * country,u8 op_class,u8 chan)19845b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
19855b9c547cSRui Paulo {
19865b9c547cSRui Paulo 	int freq;
19875b9c547cSRui Paulo 
19885b9c547cSRui Paulo 	if (country_match(us_op_class_cc, country)) {
19895b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_us(op_class, chan);
19905b9c547cSRui Paulo 		if (freq > 0)
19915b9c547cSRui Paulo 			return freq;
19925b9c547cSRui Paulo 	}
19935b9c547cSRui Paulo 
19945b9c547cSRui Paulo 	if (country_match(eu_op_class_cc, country)) {
19955b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_eu(op_class, chan);
19965b9c547cSRui Paulo 		if (freq > 0)
19975b9c547cSRui Paulo 			return freq;
19985b9c547cSRui Paulo 	}
19995b9c547cSRui Paulo 
20005b9c547cSRui Paulo 	if (country_match(jp_op_class_cc, country)) {
20015b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_jp(op_class, chan);
20025b9c547cSRui Paulo 		if (freq > 0)
20035b9c547cSRui Paulo 			return freq;
20045b9c547cSRui Paulo 	}
20055b9c547cSRui Paulo 
20065b9c547cSRui Paulo 	if (country_match(cn_op_class_cc, country)) {
20075b9c547cSRui Paulo 		freq = ieee80211_chan_to_freq_cn(op_class, chan);
20085b9c547cSRui Paulo 		if (freq > 0)
20095b9c547cSRui Paulo 			return freq;
20105b9c547cSRui Paulo 	}
20115b9c547cSRui Paulo 
20125b9c547cSRui Paulo 	return ieee80211_chan_to_freq_global(op_class, chan);
20135b9c547cSRui Paulo }
20145b9c547cSRui Paulo 
20155b9c547cSRui Paulo 
ieee80211_is_dfs(int freq,const struct hostapd_hw_modes * modes,u16 num_modes)201685732ac8SCy Schubert int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
201785732ac8SCy Schubert 		     u16 num_modes)
20185b9c547cSRui Paulo {
201985732ac8SCy Schubert 	int i, j;
202085732ac8SCy Schubert 
202185732ac8SCy Schubert 	if (!modes || !num_modes)
202285732ac8SCy Schubert 		return (freq >= 5260 && freq <= 5320) ||
2023*a90b9d01SCy Schubert 			(freq >= 5500 && freq <= 5720);
202485732ac8SCy Schubert 
202585732ac8SCy Schubert 	for (i = 0; i < num_modes; i++) {
202685732ac8SCy Schubert 		for (j = 0; j < modes[i].num_channels; j++) {
202785732ac8SCy Schubert 			if (modes[i].channels[j].freq == freq &&
202885732ac8SCy Schubert 			    (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
202985732ac8SCy Schubert 				return 1;
203085732ac8SCy Schubert 		}
203185732ac8SCy Schubert 	}
203285732ac8SCy Schubert 
203385732ac8SCy Schubert 	return 0;
20345b9c547cSRui Paulo }
20355b9c547cSRui Paulo 
20365b9c547cSRui Paulo 
20374b72b91aSCy Schubert /*
20384b72b91aSCy Schubert  * 802.11-2020: Table E-4 - Global operating classes
20394b72b91aSCy Schubert  * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123
20404b72b91aSCy Schubert  */
is_dfs_global_op_class(u8 op_class)20414b72b91aSCy Schubert int is_dfs_global_op_class(u8 op_class)
20424b72b91aSCy Schubert {
20434b72b91aSCy Schubert     return (op_class >= 118) && (op_class <= 123);
20444b72b91aSCy Schubert }
20454b72b91aSCy Schubert 
20464b72b91aSCy Schubert 
is_80plus_op_class(u8 op_class)2047*a90b9d01SCy Schubert bool is_80plus_op_class(u8 op_class)
2048*a90b9d01SCy Schubert {
2049*a90b9d01SCy Schubert 	/* Operating classes with "80+" behavior indication in Table E-4 */
2050*a90b9d01SCy Schubert 	return op_class == 130 || op_class == 135;
2051*a90b9d01SCy Schubert }
2052*a90b9d01SCy Schubert 
2053*a90b9d01SCy Schubert 
is_11b(u8 rate)20545b9c547cSRui Paulo static int is_11b(u8 rate)
20555b9c547cSRui Paulo {
20565b9c547cSRui Paulo 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
20575b9c547cSRui Paulo }
20585b9c547cSRui Paulo 
20595b9c547cSRui Paulo 
supp_rates_11b_only(struct ieee802_11_elems * elems)20605b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems)
20615b9c547cSRui Paulo {
20625b9c547cSRui Paulo 	int num_11b = 0, num_others = 0;
20635b9c547cSRui Paulo 	int i;
20645b9c547cSRui Paulo 
20655b9c547cSRui Paulo 	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
20665b9c547cSRui Paulo 		return 0;
20675b9c547cSRui Paulo 
20685b9c547cSRui Paulo 	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
20695b9c547cSRui Paulo 		if (is_11b(elems->supp_rates[i]))
20705b9c547cSRui Paulo 			num_11b++;
20715b9c547cSRui Paulo 		else
20725b9c547cSRui Paulo 			num_others++;
20735b9c547cSRui Paulo 	}
20745b9c547cSRui Paulo 
20755b9c547cSRui Paulo 	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
20765b9c547cSRui Paulo 	     i++) {
20775b9c547cSRui Paulo 		if (is_11b(elems->ext_supp_rates[i]))
20785b9c547cSRui Paulo 			num_11b++;
20795b9c547cSRui Paulo 		else
20805b9c547cSRui Paulo 			num_others++;
20815b9c547cSRui Paulo 	}
20825b9c547cSRui Paulo 
20835b9c547cSRui Paulo 	return num_11b > 0 && num_others == 0;
20845b9c547cSRui Paulo }
20855b9c547cSRui Paulo 
20865b9c547cSRui Paulo 
fc2str(u16 fc)20875b9c547cSRui Paulo const char * fc2str(u16 fc)
20885b9c547cSRui Paulo {
20895b9c547cSRui Paulo 	u16 stype = WLAN_FC_GET_STYPE(fc);
20905b9c547cSRui Paulo #define C2S(x) case x: return #x;
20915b9c547cSRui Paulo 
20925b9c547cSRui Paulo 	switch (WLAN_FC_GET_TYPE(fc)) {
20935b9c547cSRui Paulo 	case WLAN_FC_TYPE_MGMT:
20945b9c547cSRui Paulo 		switch (stype) {
20955b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ASSOC_REQ)
20965b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ASSOC_RESP)
20975b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_REASSOC_REQ)
20985b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_REASSOC_RESP)
20995b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PROBE_REQ)
21005b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PROBE_RESP)
21015b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_BEACON)
21025b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ATIM)
21035b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DISASSOC)
21045b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_AUTH)
21055b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DEAUTH)
21065b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ACTION)
21075b9c547cSRui Paulo 		}
21085b9c547cSRui Paulo 		break;
21095b9c547cSRui Paulo 	case WLAN_FC_TYPE_CTRL:
21105b9c547cSRui Paulo 		switch (stype) {
21115b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_PSPOLL)
21125b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_RTS)
21135b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CTS)
21145b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_ACK)
21155b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFEND)
21165b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFENDACK)
21175b9c547cSRui Paulo 		}
21185b9c547cSRui Paulo 		break;
21195b9c547cSRui Paulo 	case WLAN_FC_TYPE_DATA:
21205b9c547cSRui Paulo 		switch (stype) {
21215b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA)
21225b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFACK)
21235b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFPOLL)
21245b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
21255b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_NULLFUNC)
21265b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFACK)
21275b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFPOLL)
21285b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_CFACKPOLL)
21295b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA)
21305b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
21315b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
21325b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
21335b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_NULL)
21345b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_CFPOLL)
21355b9c547cSRui Paulo 		C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
21365b9c547cSRui Paulo 		}
21375b9c547cSRui Paulo 		break;
21385b9c547cSRui Paulo 	}
21395b9c547cSRui Paulo 	return "WLAN_FC_TYPE_UNKNOWN";
21405b9c547cSRui Paulo #undef C2S
21415b9c547cSRui Paulo }
2142325151a3SRui Paulo 
2143325151a3SRui Paulo 
reason2str(u16 reason)2144206b73d0SCy Schubert const char * reason2str(u16 reason)
2145206b73d0SCy Schubert {
2146206b73d0SCy Schubert #define R2S(r) case WLAN_REASON_ ## r: return #r;
2147206b73d0SCy Schubert 	switch (reason) {
2148206b73d0SCy Schubert 	R2S(UNSPECIFIED)
2149206b73d0SCy Schubert 	R2S(PREV_AUTH_NOT_VALID)
2150206b73d0SCy Schubert 	R2S(DEAUTH_LEAVING)
2151206b73d0SCy Schubert 	R2S(DISASSOC_DUE_TO_INACTIVITY)
2152206b73d0SCy Schubert 	R2S(DISASSOC_AP_BUSY)
2153206b73d0SCy Schubert 	R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
2154206b73d0SCy Schubert 	R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
2155206b73d0SCy Schubert 	R2S(DISASSOC_STA_HAS_LEFT)
2156206b73d0SCy Schubert 	R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
2157206b73d0SCy Schubert 	R2S(PWR_CAPABILITY_NOT_VALID)
2158206b73d0SCy Schubert 	R2S(SUPPORTED_CHANNEL_NOT_VALID)
2159206b73d0SCy Schubert 	R2S(BSS_TRANSITION_DISASSOC)
2160206b73d0SCy Schubert 	R2S(INVALID_IE)
2161206b73d0SCy Schubert 	R2S(MICHAEL_MIC_FAILURE)
2162206b73d0SCy Schubert 	R2S(4WAY_HANDSHAKE_TIMEOUT)
2163206b73d0SCy Schubert 	R2S(GROUP_KEY_UPDATE_TIMEOUT)
2164206b73d0SCy Schubert 	R2S(IE_IN_4WAY_DIFFERS)
2165206b73d0SCy Schubert 	R2S(GROUP_CIPHER_NOT_VALID)
2166206b73d0SCy Schubert 	R2S(PAIRWISE_CIPHER_NOT_VALID)
2167206b73d0SCy Schubert 	R2S(AKMP_NOT_VALID)
2168206b73d0SCy Schubert 	R2S(UNSUPPORTED_RSN_IE_VERSION)
2169206b73d0SCy Schubert 	R2S(INVALID_RSN_IE_CAPAB)
2170206b73d0SCy Schubert 	R2S(IEEE_802_1X_AUTH_FAILED)
2171206b73d0SCy Schubert 	R2S(CIPHER_SUITE_REJECTED)
2172206b73d0SCy Schubert 	R2S(TDLS_TEARDOWN_UNREACHABLE)
2173206b73d0SCy Schubert 	R2S(TDLS_TEARDOWN_UNSPECIFIED)
2174206b73d0SCy Schubert 	R2S(SSP_REQUESTED_DISASSOC)
2175206b73d0SCy Schubert 	R2S(NO_SSP_ROAMING_AGREEMENT)
2176206b73d0SCy Schubert 	R2S(BAD_CIPHER_OR_AKM)
2177206b73d0SCy Schubert 	R2S(NOT_AUTHORIZED_THIS_LOCATION)
2178206b73d0SCy Schubert 	R2S(SERVICE_CHANGE_PRECLUDES_TS)
2179206b73d0SCy Schubert 	R2S(UNSPECIFIED_QOS_REASON)
2180206b73d0SCy Schubert 	R2S(NOT_ENOUGH_BANDWIDTH)
2181206b73d0SCy Schubert 	R2S(DISASSOC_LOW_ACK)
2182206b73d0SCy Schubert 	R2S(EXCEEDED_TXOP)
2183206b73d0SCy Schubert 	R2S(STA_LEAVING)
2184206b73d0SCy Schubert 	R2S(END_TS_BA_DLS)
2185206b73d0SCy Schubert 	R2S(UNKNOWN_TS_BA)
2186206b73d0SCy Schubert 	R2S(TIMEOUT)
2187206b73d0SCy Schubert 	R2S(PEERKEY_MISMATCH)
2188206b73d0SCy Schubert 	R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
2189206b73d0SCy Schubert 	R2S(EXTERNAL_SERVICE_REQUIREMENTS)
2190206b73d0SCy Schubert 	R2S(INVALID_FT_ACTION_FRAME_COUNT)
2191206b73d0SCy Schubert 	R2S(INVALID_PMKID)
2192206b73d0SCy Schubert 	R2S(INVALID_MDE)
2193206b73d0SCy Schubert 	R2S(INVALID_FTE)
2194206b73d0SCy Schubert 	R2S(MESH_PEERING_CANCELLED)
2195206b73d0SCy Schubert 	R2S(MESH_MAX_PEERS)
2196206b73d0SCy Schubert 	R2S(MESH_CONFIG_POLICY_VIOLATION)
2197206b73d0SCy Schubert 	R2S(MESH_CLOSE_RCVD)
2198206b73d0SCy Schubert 	R2S(MESH_MAX_RETRIES)
2199206b73d0SCy Schubert 	R2S(MESH_CONFIRM_TIMEOUT)
2200206b73d0SCy Schubert 	R2S(MESH_INVALID_GTK)
2201206b73d0SCy Schubert 	R2S(MESH_INCONSISTENT_PARAMS)
2202206b73d0SCy Schubert 	R2S(MESH_INVALID_SECURITY_CAP)
2203206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
2204206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
2205206b73d0SCy Schubert 	R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
2206206b73d0SCy Schubert 	R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
2207206b73d0SCy Schubert 	R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
2208206b73d0SCy Schubert 	R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
2209206b73d0SCy Schubert 	}
2210206b73d0SCy Schubert 	return "UNKNOWN";
2211206b73d0SCy Schubert #undef R2S
2212206b73d0SCy Schubert }
2213206b73d0SCy Schubert 
2214206b73d0SCy Schubert 
status2str(u16 status)2215206b73d0SCy Schubert const char * status2str(u16 status)
2216206b73d0SCy Schubert {
2217206b73d0SCy Schubert #define S2S(s) case WLAN_STATUS_ ## s: return #s;
2218206b73d0SCy Schubert 	switch (status) {
2219206b73d0SCy Schubert 	S2S(SUCCESS)
2220206b73d0SCy Schubert 	S2S(UNSPECIFIED_FAILURE)
2221206b73d0SCy Schubert 	S2S(TDLS_WAKEUP_ALTERNATE)
2222206b73d0SCy Schubert 	S2S(TDLS_WAKEUP_REJECT)
2223206b73d0SCy Schubert 	S2S(SECURITY_DISABLED)
2224206b73d0SCy Schubert 	S2S(UNACCEPTABLE_LIFETIME)
2225206b73d0SCy Schubert 	S2S(NOT_IN_SAME_BSS)
2226206b73d0SCy Schubert 	S2S(CAPS_UNSUPPORTED)
2227206b73d0SCy Schubert 	S2S(REASSOC_NO_ASSOC)
2228206b73d0SCy Schubert 	S2S(ASSOC_DENIED_UNSPEC)
2229206b73d0SCy Schubert 	S2S(NOT_SUPPORTED_AUTH_ALG)
2230206b73d0SCy Schubert 	S2S(UNKNOWN_AUTH_TRANSACTION)
2231206b73d0SCy Schubert 	S2S(CHALLENGE_FAIL)
2232206b73d0SCy Schubert 	S2S(AUTH_TIMEOUT)
2233206b73d0SCy Schubert 	S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
2234206b73d0SCy Schubert 	S2S(ASSOC_DENIED_RATES)
2235206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NOSHORT)
2236206b73d0SCy Schubert 	S2S(SPEC_MGMT_REQUIRED)
2237206b73d0SCy Schubert 	S2S(PWR_CAPABILITY_NOT_VALID)
2238206b73d0SCy Schubert 	S2S(SUPPORTED_CHANNEL_NOT_VALID)
2239206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
2240206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_HT)
2241206b73d0SCy Schubert 	S2S(R0KH_UNREACHABLE)
2242206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_PCO)
2243206b73d0SCy Schubert 	S2S(ASSOC_REJECTED_TEMPORARILY)
2244206b73d0SCy Schubert 	S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
2245206b73d0SCy Schubert 	S2S(UNSPECIFIED_QOS_FAILURE)
2246206b73d0SCy Schubert 	S2S(DENIED_INSUFFICIENT_BANDWIDTH)
2247206b73d0SCy Schubert 	S2S(DENIED_POOR_CHANNEL_CONDITIONS)
2248206b73d0SCy Schubert 	S2S(DENIED_QOS_NOT_SUPPORTED)
2249206b73d0SCy Schubert 	S2S(REQUEST_DECLINED)
2250206b73d0SCy Schubert 	S2S(INVALID_PARAMETERS)
2251206b73d0SCy Schubert 	S2S(REJECTED_WITH_SUGGESTED_CHANGES)
2252206b73d0SCy Schubert 	S2S(INVALID_IE)
2253206b73d0SCy Schubert 	S2S(GROUP_CIPHER_NOT_VALID)
2254206b73d0SCy Schubert 	S2S(PAIRWISE_CIPHER_NOT_VALID)
2255206b73d0SCy Schubert 	S2S(AKMP_NOT_VALID)
2256206b73d0SCy Schubert 	S2S(UNSUPPORTED_RSN_IE_VERSION)
2257206b73d0SCy Schubert 	S2S(INVALID_RSN_IE_CAPAB)
2258206b73d0SCy Schubert 	S2S(CIPHER_REJECTED_PER_POLICY)
2259206b73d0SCy Schubert 	S2S(TS_NOT_CREATED)
2260206b73d0SCy Schubert 	S2S(DIRECT_LINK_NOT_ALLOWED)
2261206b73d0SCy Schubert 	S2S(DEST_STA_NOT_PRESENT)
2262206b73d0SCy Schubert 	S2S(DEST_STA_NOT_QOS_STA)
2263206b73d0SCy Schubert 	S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
2264206b73d0SCy Schubert 	S2S(INVALID_FT_ACTION_FRAME_COUNT)
2265206b73d0SCy Schubert 	S2S(INVALID_PMKID)
2266206b73d0SCy Schubert 	S2S(INVALID_MDIE)
2267206b73d0SCy Schubert 	S2S(INVALID_FTIE)
2268206b73d0SCy Schubert 	S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
2269206b73d0SCy Schubert 	S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
2270206b73d0SCy Schubert 	S2S(TRY_ANOTHER_BSS)
2271206b73d0SCy Schubert 	S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
2272206b73d0SCy Schubert 	S2S(NO_OUTSTANDING_GAS_REQ)
2273206b73d0SCy Schubert 	S2S(GAS_RESP_NOT_RECEIVED)
2274206b73d0SCy Schubert 	S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
2275206b73d0SCy Schubert 	S2S(GAS_RESP_LARGER_THAN_LIMIT)
2276206b73d0SCy Schubert 	S2S(REQ_REFUSED_HOME)
2277206b73d0SCy Schubert 	S2S(ADV_SRV_UNREACHABLE)
2278206b73d0SCy Schubert 	S2S(REQ_REFUSED_SSPN)
2279206b73d0SCy Schubert 	S2S(REQ_REFUSED_UNAUTH_ACCESS)
2280206b73d0SCy Schubert 	S2S(INVALID_RSNIE)
2281206b73d0SCy Schubert 	S2S(U_APSD_COEX_NOT_SUPPORTED)
2282206b73d0SCy Schubert 	S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
2283206b73d0SCy Schubert 	S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
2284206b73d0SCy Schubert 	S2S(ANTI_CLOGGING_TOKEN_REQ)
2285206b73d0SCy Schubert 	S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
2286206b73d0SCy Schubert 	S2S(CANNOT_FIND_ALT_TBTT)
2287206b73d0SCy Schubert 	S2S(TRANSMISSION_FAILURE)
2288206b73d0SCy Schubert 	S2S(REQ_TCLAS_NOT_SUPPORTED)
2289206b73d0SCy Schubert 	S2S(TCLAS_RESOURCES_EXCHAUSTED)
2290206b73d0SCy Schubert 	S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
2291206b73d0SCy Schubert 	S2S(REJECT_WITH_SCHEDULE)
2292206b73d0SCy Schubert 	S2S(REJECT_NO_WAKEUP_SPECIFIED)
2293206b73d0SCy Schubert 	S2S(SUCCESS_POWER_SAVE_MODE)
2294206b73d0SCy Schubert 	S2S(PENDING_ADMITTING_FST_SESSION)
2295206b73d0SCy Schubert 	S2S(PERFORMING_FST_NOW)
2296206b73d0SCy Schubert 	S2S(PENDING_GAP_IN_BA_WINDOW)
2297206b73d0SCy Schubert 	S2S(REJECT_U_PID_SETTING)
2298206b73d0SCy Schubert 	S2S(REFUSED_EXTERNAL_REASON)
2299206b73d0SCy Schubert 	S2S(REFUSED_AP_OUT_OF_MEMORY)
2300206b73d0SCy Schubert 	S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
2301206b73d0SCy Schubert 	S2S(QUERY_RESP_OUTSTANDING)
2302206b73d0SCy Schubert 	S2S(REJECT_DSE_BAND)
2303206b73d0SCy Schubert 	S2S(TCLAS_PROCESSING_TERMINATED)
2304206b73d0SCy Schubert 	S2S(TS_SCHEDULE_CONFLICT)
2305206b73d0SCy Schubert 	S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
2306206b73d0SCy Schubert 	S2S(MCCAOP_RESERVATION_CONFLICT)
2307206b73d0SCy Schubert 	S2S(MAF_LIMIT_EXCEEDED)
2308206b73d0SCy Schubert 	S2S(MCCA_TRACK_LIMIT_EXCEEDED)
2309206b73d0SCy Schubert 	S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
2310206b73d0SCy Schubert 	S2S(ASSOC_DENIED_NO_VHT)
2311206b73d0SCy Schubert 	S2S(ENABLEMENT_DENIED)
2312206b73d0SCy Schubert 	S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
2313206b73d0SCy Schubert 	S2S(AUTHORIZATION_DEENABLED)
2314206b73d0SCy Schubert 	S2S(FILS_AUTHENTICATION_FAILURE)
2315206b73d0SCy Schubert 	S2S(UNKNOWN_AUTHENTICATION_SERVER)
2316206b73d0SCy Schubert 	S2S(UNKNOWN_PASSWORD_IDENTIFIER)
2317c1d255d3SCy Schubert 	S2S(DENIED_HE_NOT_SUPPORTED)
2318c1d255d3SCy Schubert 	S2S(SAE_HASH_TO_ELEMENT)
2319c1d255d3SCy Schubert 	S2S(SAE_PK)
2320*a90b9d01SCy Schubert 	S2S(INVALID_PUBLIC_KEY)
2321*a90b9d01SCy Schubert 	S2S(PASN_BASE_AKMP_FAILED)
2322*a90b9d01SCy Schubert 	S2S(OCI_MISMATCH)
2323206b73d0SCy Schubert 	}
2324206b73d0SCy Schubert 	return "UNKNOWN";
2325206b73d0SCy Schubert #undef S2S
2326206b73d0SCy Schubert }
2327206b73d0SCy Schubert 
2328206b73d0SCy Schubert 
mb_ies_info_by_ies(struct mb_ies_info * info,const u8 * ies_buf,size_t ies_len)2329325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
2330325151a3SRui Paulo 		       size_t ies_len)
2331325151a3SRui Paulo {
23324bc52338SCy Schubert 	const struct element *elem;
23334bc52338SCy Schubert 
2334325151a3SRui Paulo 	os_memset(info, 0, sizeof(*info));
2335325151a3SRui Paulo 
23364bc52338SCy Schubert 	if (!ies_buf)
23374bc52338SCy Schubert 		return 0;
2338325151a3SRui Paulo 
23394bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
23404bc52338SCy Schubert 		if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
23414bc52338SCy Schubert 			return 0;
2342325151a3SRui Paulo 
23434bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
23444bc52338SCy Schubert 			   elem->datalen + 2);
23454bc52338SCy Schubert 		info->ies[info->nof_ies].ie = elem->data;
23464bc52338SCy Schubert 		info->ies[info->nof_ies].ie_len = elem->datalen;
2347325151a3SRui Paulo 		info->nof_ies++;
2348325151a3SRui Paulo 	}
2349325151a3SRui Paulo 
23504bc52338SCy Schubert 	if (!for_each_element_completed(elem, ies_buf, ies_len)) {
23514bc52338SCy Schubert 		wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
23524bc52338SCy Schubert 		return -1;
2353325151a3SRui Paulo 	}
2354325151a3SRui Paulo 
2355325151a3SRui Paulo 	return 0;
2356325151a3SRui Paulo }
2357325151a3SRui Paulo 
2358325151a3SRui Paulo 
mb_ies_by_info(struct mb_ies_info * info)2359325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
2360325151a3SRui Paulo {
2361325151a3SRui Paulo 	struct wpabuf *mb_ies = NULL;
2362325151a3SRui Paulo 
2363325151a3SRui Paulo 	WPA_ASSERT(info != NULL);
2364325151a3SRui Paulo 
2365325151a3SRui Paulo 	if (info->nof_ies) {
2366325151a3SRui Paulo 		u8 i;
2367325151a3SRui Paulo 		size_t mb_ies_size = 0;
2368325151a3SRui Paulo 
2369325151a3SRui Paulo 		for (i = 0; i < info->nof_ies; i++)
2370325151a3SRui Paulo 			mb_ies_size += 2 + info->ies[i].ie_len;
2371325151a3SRui Paulo 
2372325151a3SRui Paulo 		mb_ies = wpabuf_alloc(mb_ies_size);
2373325151a3SRui Paulo 		if (mb_ies) {
2374325151a3SRui Paulo 			for (i = 0; i < info->nof_ies; i++) {
2375325151a3SRui Paulo 				wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
2376325151a3SRui Paulo 				wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
2377325151a3SRui Paulo 				wpabuf_put_data(mb_ies,
2378325151a3SRui Paulo 						info->ies[i].ie,
2379325151a3SRui Paulo 						info->ies[i].ie_len);
2380325151a3SRui Paulo 			}
2381325151a3SRui Paulo 		}
2382325151a3SRui Paulo 	}
2383325151a3SRui Paulo 
2384325151a3SRui Paulo 	return mb_ies;
2385325151a3SRui Paulo }
2386780fb4a2SCy Schubert 
2387780fb4a2SCy Schubert 
2388780fb4a2SCy Schubert const struct oper_class_map global_op_class[] = {
2389780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
2390780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
2391780fb4a2SCy Schubert 
2392780fb4a2SCy Schubert 	/* Do not enable HT40 on 2.4 GHz for P2P use for now */
2393780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
2394780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
2395780fb4a2SCy Schubert 
2396780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
2397780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
2398780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
2399780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
2400780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
2401780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
2402*a90b9d01SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP },
2403*a90b9d01SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP },
2404*a90b9d01SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP },
2405780fb4a2SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
2406c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
2407c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
2408c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
2409780fb4a2SCy Schubert 
2410780fb4a2SCy Schubert 	/*
2411*a90b9d01SCy Schubert 	 * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center
2412*a90b9d01SCy Schubert 	 * frequency index for operation classes 128, 129, 130, 132, 133, 134,
2413*a90b9d01SCy Schubert 	 * and 135, but currently use the lowest 20 MHz channel for simplicity
2414780fb4a2SCy Schubert 	 * (these center frequencies are not actual channels, which makes
2415*a90b9d01SCy Schubert 	 * wpas_p2p_verify_channel() fail).
2416*a90b9d01SCy Schubert 	 * Specially for the operation class 136, it is also defined to use the
2417*a90b9d01SCy Schubert 	 * channel center frequency index value, but it happens to be a 20 MHz
2418*a90b9d01SCy Schubert 	 * channel and the channel number in the channel set would match the
2419*a90b9d01SCy Schubert 	 * value in for the frequency center.
2420*a90b9d01SCy Schubert 	 *
2421*a90b9d01SCy Schubert 	 * Operating class value pair 128 and 130 is used to describe a 80+80
2422*a90b9d01SCy Schubert 	 * MHz channel on the 5 GHz band. 130 is identified with "80+", so this
2423*a90b9d01SCy Schubert 	 * is encoded with two octets 130 and 128. Similarly, operating class
2424*a90b9d01SCy Schubert 	 * value pair 133 and 135 is used to describe a 80+80 MHz channel on
2425*a90b9d01SCy Schubert 	 * the 6 GHz band (135 being the one with "80+" indication). All other
2426*a90b9d01SCy Schubert 	 * operating classes listed here are used as 1-octet values.
2427780fb4a2SCy Schubert 	 */
2428c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
2429c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
2430*a90b9d01SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
2431c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
24324b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP },
24334b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP },
24344b72b91aSCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP },
2435c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
2436c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
2437c1d255d3SCy Schubert 
2438*a90b9d01SCy Schubert 	/* IEEE P802.11be/D5.0, Table E-4 (Global operating classes) */
2439*a90b9d01SCy Schubert 	{ HOSTAPD_MODE_IEEE80211A, 137, 31, 191, 32, BW320, NO_P2P_SUPP },
2440*a90b9d01SCy Schubert 
2441c1d255d3SCy Schubert 	/*
2442c1d255d3SCy Schubert 	 * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
2443c1d255d3SCy Schubert 	 * Class 180 has the legacy channels 1-6. Classes 181-183 include
2444c1d255d3SCy Schubert 	 * channels which implement channel bonding features.
2445c1d255d3SCy Schubert 	 */
2446c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP },
2447c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
2448c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
2449c1d255d3SCy Schubert 	{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
2450c1d255d3SCy Schubert 
2451780fb4a2SCy Schubert 	{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
2452780fb4a2SCy Schubert };
2453780fb4a2SCy Schubert 
2454780fb4a2SCy Schubert 
ieee80211_phy_type_by_freq(int freq)2455780fb4a2SCy Schubert static enum phy_type ieee80211_phy_type_by_freq(int freq)
2456780fb4a2SCy Schubert {
2457780fb4a2SCy Schubert 	enum hostapd_hw_mode hw_mode;
2458780fb4a2SCy Schubert 	u8 channel;
2459780fb4a2SCy Schubert 
2460780fb4a2SCy Schubert 	hw_mode = ieee80211_freq_to_chan(freq, &channel);
2461780fb4a2SCy Schubert 
2462780fb4a2SCy Schubert 	switch (hw_mode) {
2463780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211A:
2464780fb4a2SCy Schubert 		return PHY_TYPE_OFDM;
2465780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211B:
2466780fb4a2SCy Schubert 		return PHY_TYPE_HRDSSS;
2467780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211G:
2468780fb4a2SCy Schubert 		return PHY_TYPE_ERP;
2469780fb4a2SCy Schubert 	case HOSTAPD_MODE_IEEE80211AD:
2470780fb4a2SCy Schubert 		return PHY_TYPE_DMG;
2471780fb4a2SCy Schubert 	default:
2472780fb4a2SCy Schubert 		return PHY_TYPE_UNSPECIFIED;
2473780fb4a2SCy Schubert 	};
2474780fb4a2SCy Schubert }
2475780fb4a2SCy Schubert 
2476780fb4a2SCy Schubert 
2477780fb4a2SCy Schubert /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
ieee80211_get_phy_type(int freq,int ht,int vht)2478780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
2479780fb4a2SCy Schubert {
2480780fb4a2SCy Schubert 	if (vht)
2481780fb4a2SCy Schubert 		return PHY_TYPE_VHT;
2482780fb4a2SCy Schubert 	if (ht)
2483780fb4a2SCy Schubert 		return PHY_TYPE_HT;
2484780fb4a2SCy Schubert 
2485780fb4a2SCy Schubert 	return ieee80211_phy_type_by_freq(freq);
2486780fb4a2SCy Schubert }
2487780fb4a2SCy Schubert 
2488780fb4a2SCy Schubert 
2489780fb4a2SCy Schubert size_t global_op_class_size = ARRAY_SIZE(global_op_class);
2490780fb4a2SCy Schubert 
2491780fb4a2SCy Schubert 
2492780fb4a2SCy Schubert /**
2493780fb4a2SCy Schubert  * get_ie - Fetch a specified information element from IEs buffer
2494780fb4a2SCy Schubert  * @ies: Information elements buffer
2495780fb4a2SCy Schubert  * @len: Information elements buffer length
2496780fb4a2SCy Schubert  * @eid: Information element identifier (WLAN_EID_*)
2497780fb4a2SCy Schubert  * Returns: Pointer to the information element (id field) or %NULL if not found
2498780fb4a2SCy Schubert  *
2499780fb4a2SCy Schubert  * This function returns the first matching information element in the IEs
2500780fb4a2SCy Schubert  * buffer or %NULL in case the element is not found.
2501780fb4a2SCy Schubert  */
get_ie(const u8 * ies,size_t len,u8 eid)2502780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
2503780fb4a2SCy Schubert {
25044bc52338SCy Schubert 	const struct element *elem;
2505780fb4a2SCy Schubert 
2506780fb4a2SCy Schubert 	if (!ies)
2507780fb4a2SCy Schubert 		return NULL;
2508780fb4a2SCy Schubert 
25094bc52338SCy Schubert 	for_each_element_id(elem, eid, ies, len)
25104bc52338SCy Schubert 		return &elem->id;
2511780fb4a2SCy Schubert 
2512780fb4a2SCy Schubert 	return NULL;
2513780fb4a2SCy Schubert }
2514780fb4a2SCy Schubert 
2515780fb4a2SCy Schubert 
251685732ac8SCy Schubert /**
251785732ac8SCy Schubert  * get_ie_ext - Fetch a specified extended information element from IEs buffer
251885732ac8SCy Schubert  * @ies: Information elements buffer
251985732ac8SCy Schubert  * @len: Information elements buffer length
252085732ac8SCy Schubert  * @ext: Information element extension identifier (WLAN_EID_EXT_*)
252185732ac8SCy Schubert  * Returns: Pointer to the information element (id field) or %NULL if not found
252285732ac8SCy Schubert  *
252385732ac8SCy Schubert  * This function returns the first matching information element in the IEs
252485732ac8SCy Schubert  * buffer or %NULL in case the element is not found.
252585732ac8SCy Schubert  */
get_ie_ext(const u8 * ies,size_t len,u8 ext)252685732ac8SCy Schubert const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
252785732ac8SCy Schubert {
25284bc52338SCy Schubert 	const struct element *elem;
252985732ac8SCy Schubert 
253085732ac8SCy Schubert 	if (!ies)
253185732ac8SCy Schubert 		return NULL;
253285732ac8SCy Schubert 
25334bc52338SCy Schubert 	for_each_element_extid(elem, ext, ies, len)
25344bc52338SCy Schubert 		return &elem->id;
253585732ac8SCy Schubert 
25364bc52338SCy Schubert 	return NULL;
25374bc52338SCy Schubert }
253885732ac8SCy Schubert 
253985732ac8SCy Schubert 
get_vendor_ie(const u8 * ies,size_t len,u32 vendor_type)25404bc52338SCy Schubert const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
25414bc52338SCy Schubert {
25424bc52338SCy Schubert 	const struct element *elem;
25434bc52338SCy Schubert 
25444bc52338SCy Schubert 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
25454bc52338SCy Schubert 		if (elem->datalen >= 4 &&
25464bc52338SCy Schubert 		    vendor_type == WPA_GET_BE32(elem->data))
25474bc52338SCy Schubert 			return &elem->id;
254885732ac8SCy Schubert 	}
254985732ac8SCy Schubert 
255085732ac8SCy Schubert 	return NULL;
255185732ac8SCy Schubert }
255285732ac8SCy Schubert 
255385732ac8SCy Schubert 
mbo_add_ie(u8 * buf,size_t len,const u8 * attr,size_t attr_len)2554780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
2555780fb4a2SCy Schubert {
2556780fb4a2SCy Schubert 	/*
2557780fb4a2SCy Schubert 	 * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
2558780fb4a2SCy Schubert 	 * OUI (3), OUI type (1).
2559780fb4a2SCy Schubert 	 */
2560780fb4a2SCy Schubert 	if (len < 6 + attr_len) {
2561780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
2562780fb4a2SCy Schubert 			   "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
2563780fb4a2SCy Schubert 			   len, attr_len);
2564780fb4a2SCy Schubert 		return 0;
2565780fb4a2SCy Schubert 	}
2566780fb4a2SCy Schubert 
2567780fb4a2SCy Schubert 	*buf++ = WLAN_EID_VENDOR_SPECIFIC;
2568780fb4a2SCy Schubert 	*buf++ = attr_len + 4;
2569780fb4a2SCy Schubert 	WPA_PUT_BE24(buf, OUI_WFA);
2570780fb4a2SCy Schubert 	buf += 3;
2571780fb4a2SCy Schubert 	*buf++ = MBO_OUI_TYPE;
2572780fb4a2SCy Schubert 	os_memcpy(buf, attr, attr_len);
2573780fb4a2SCy Schubert 
2574780fb4a2SCy Schubert 	return 6 + attr_len;
2575780fb4a2SCy Schubert }
257685732ac8SCy Schubert 
257785732ac8SCy Schubert 
check_multi_ap_ie(const u8 * multi_ap_ie,size_t multi_ap_len,struct multi_ap_params * multi_ap)2578*a90b9d01SCy Schubert u16 check_multi_ap_ie(const u8 *multi_ap_ie, size_t multi_ap_len,
2579*a90b9d01SCy Schubert 		      struct multi_ap_params *multi_ap)
2580*a90b9d01SCy Schubert {
2581*a90b9d01SCy Schubert 	const struct element *elem;
2582*a90b9d01SCy Schubert 	bool ext_present = false;
2583*a90b9d01SCy Schubert 	unsigned int vlan_id;
2584*a90b9d01SCy Schubert 
2585*a90b9d01SCy Schubert 	os_memset(multi_ap, 0, sizeof(*multi_ap));
2586*a90b9d01SCy Schubert 
2587*a90b9d01SCy Schubert 	/* Default profile is 1, when Multi-AP profile subelement is not
2588*a90b9d01SCy Schubert 	 * present in the element. */
2589*a90b9d01SCy Schubert 	multi_ap->profile = 1;
2590*a90b9d01SCy Schubert 
2591*a90b9d01SCy Schubert 	for_each_element(elem, multi_ap_ie, multi_ap_len) {
2592*a90b9d01SCy Schubert 		u8 id = elem->id, elen = elem->datalen;
2593*a90b9d01SCy Schubert 		const u8 *pos = elem->data;
2594*a90b9d01SCy Schubert 
2595*a90b9d01SCy Schubert 		switch (id) {
2596*a90b9d01SCy Schubert 		case MULTI_AP_SUB_ELEM_TYPE:
2597*a90b9d01SCy Schubert 			if (elen >= 1) {
2598*a90b9d01SCy Schubert 				multi_ap->capability = *pos;
2599*a90b9d01SCy Schubert 				ext_present = true;
2600*a90b9d01SCy Schubert 			} else {
2601*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2602*a90b9d01SCy Schubert 					   "Multi-AP invalid Multi-AP subelement");
2603*a90b9d01SCy Schubert 				return WLAN_STATUS_INVALID_IE;
2604*a90b9d01SCy Schubert 			}
2605*a90b9d01SCy Schubert 			break;
2606*a90b9d01SCy Schubert 		case MULTI_AP_PROFILE_SUB_ELEM_TYPE:
2607*a90b9d01SCy Schubert 			if (elen < 1) {
2608*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2609*a90b9d01SCy Schubert 					   "Multi-AP IE invalid Multi-AP profile subelement");
2610*a90b9d01SCy Schubert 				return WLAN_STATUS_INVALID_IE;
2611*a90b9d01SCy Schubert 			}
2612*a90b9d01SCy Schubert 
2613*a90b9d01SCy Schubert 			multi_ap->profile = *pos;
2614*a90b9d01SCy Schubert 			if (multi_ap->profile > MULTI_AP_PROFILE_MAX) {
2615*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2616*a90b9d01SCy Schubert 					   "Multi-AP IE with invalid profile 0x%02x",
2617*a90b9d01SCy Schubert 					   multi_ap->profile);
2618*a90b9d01SCy Schubert 				return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
2619*a90b9d01SCy Schubert 			}
2620*a90b9d01SCy Schubert 			break;
2621*a90b9d01SCy Schubert 		case MULTI_AP_VLAN_SUB_ELEM_TYPE:
2622*a90b9d01SCy Schubert 			if (multi_ap->profile < MULTI_AP_PROFILE_2) {
2623*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2624*a90b9d01SCy Schubert 					   "Multi-AP IE invalid profile to read VLAN IE");
2625*a90b9d01SCy Schubert 				return WLAN_STATUS_INVALID_IE;
2626*a90b9d01SCy Schubert 			}
2627*a90b9d01SCy Schubert 			if (elen < 2) {
2628*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2629*a90b9d01SCy Schubert 					   "Multi-AP IE invalid Multi-AP VLAN subelement");
2630*a90b9d01SCy Schubert 				return WLAN_STATUS_INVALID_IE;
2631*a90b9d01SCy Schubert 			}
2632*a90b9d01SCy Schubert 
2633*a90b9d01SCy Schubert 			vlan_id = WPA_GET_LE16(pos);
2634*a90b9d01SCy Schubert 			if (vlan_id < 1 || vlan_id > 4094) {
2635*a90b9d01SCy Schubert 				wpa_printf(MSG_INFO,
2636*a90b9d01SCy Schubert 					   "Multi-AP IE invalid Multi-AP VLAN ID %d",
2637*a90b9d01SCy Schubert 					   vlan_id);
2638*a90b9d01SCy Schubert 				return WLAN_STATUS_INVALID_IE;
2639*a90b9d01SCy Schubert 			}
2640*a90b9d01SCy Schubert 			multi_ap->vlanid = vlan_id;
2641*a90b9d01SCy Schubert 			break;
2642*a90b9d01SCy Schubert 		default:
2643*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
2644*a90b9d01SCy Schubert 				   "Ignore unknown subelement %u in Multi-AP IE",
2645*a90b9d01SCy Schubert 				   id);
2646*a90b9d01SCy Schubert 			break;
2647*a90b9d01SCy Schubert 		}
2648*a90b9d01SCy Schubert 	}
2649*a90b9d01SCy Schubert 
2650*a90b9d01SCy Schubert 	if (!for_each_element_completed(elem, multi_ap_ie, multi_ap_len)) {
2651*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "Multi AP IE parse failed @%d",
2652*a90b9d01SCy Schubert 			   (int) (multi_ap_ie + multi_ap_len -
2653*a90b9d01SCy Schubert 				  (const u8 *) elem));
2654*a90b9d01SCy Schubert 		wpa_hexdump(MSG_MSGDUMP, "IEs", multi_ap_ie, multi_ap_len);
2655*a90b9d01SCy Schubert 	}
2656*a90b9d01SCy Schubert 
2657*a90b9d01SCy Schubert 	if (!ext_present) {
2658*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
2659*a90b9d01SCy Schubert 			   "Multi-AP element without Multi-AP Extension subelement");
2660*a90b9d01SCy Schubert 		return WLAN_STATUS_INVALID_IE;
2661*a90b9d01SCy Schubert 	}
2662*a90b9d01SCy Schubert 
2663*a90b9d01SCy Schubert 	return WLAN_STATUS_SUCCESS;
2664*a90b9d01SCy Schubert }
2665*a90b9d01SCy Schubert 
2666*a90b9d01SCy Schubert 
add_multi_ap_ie(u8 * buf,size_t len,const struct multi_ap_params * multi_ap)2667*a90b9d01SCy Schubert size_t add_multi_ap_ie(u8 *buf, size_t len,
2668*a90b9d01SCy Schubert 		       const struct multi_ap_params *multi_ap)
26694bc52338SCy Schubert {
26704bc52338SCy Schubert 	u8 *pos = buf;
2671*a90b9d01SCy Schubert 	u8 *len_ptr;
26724bc52338SCy Schubert 
2673*a90b9d01SCy Schubert 	if (len < 6)
26744bc52338SCy Schubert 		return 0;
26754bc52338SCy Schubert 
26764bc52338SCy Schubert 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
2677*a90b9d01SCy Schubert 	len_ptr = pos; /* Length field to be set at the end */
2678*a90b9d01SCy Schubert 	pos++;
26794bc52338SCy Schubert 	WPA_PUT_BE24(pos, OUI_WFA);
26804bc52338SCy Schubert 	pos += 3;
26814bc52338SCy Schubert 	*pos++ = MULTI_AP_OUI_TYPE;
2682*a90b9d01SCy Schubert 
2683*a90b9d01SCy Schubert 	/* Multi-AP Extension subelement */
2684*a90b9d01SCy Schubert 	if (buf + len - pos < 3)
2685*a90b9d01SCy Schubert 		return 0;
26864bc52338SCy Schubert 	*pos++ = MULTI_AP_SUB_ELEM_TYPE;
26874bc52338SCy Schubert 	*pos++ = 1; /* len */
2688*a90b9d01SCy Schubert 	*pos++ = multi_ap->capability;
2689*a90b9d01SCy Schubert 
2690*a90b9d01SCy Schubert 	/* Add Multi-AP Profile subelement only for R2 or newer configuration */
2691*a90b9d01SCy Schubert 	if (multi_ap->profile >= MULTI_AP_PROFILE_2) {
2692*a90b9d01SCy Schubert 		if (buf + len - pos < 3)
2693*a90b9d01SCy Schubert 			return 0;
2694*a90b9d01SCy Schubert 		*pos++ = MULTI_AP_PROFILE_SUB_ELEM_TYPE;
2695*a90b9d01SCy Schubert 		*pos++ = 1;
2696*a90b9d01SCy Schubert 		*pos++ = multi_ap->profile;
2697*a90b9d01SCy Schubert 	}
2698*a90b9d01SCy Schubert 
2699*a90b9d01SCy Schubert 	/* Add Multi-AP Default 802.1Q Setting subelement only for backhaul BSS
2700*a90b9d01SCy Schubert 	 */
2701*a90b9d01SCy Schubert 	if (multi_ap->vlanid &&
2702*a90b9d01SCy Schubert 	    multi_ap->profile >= MULTI_AP_PROFILE_2 &&
2703*a90b9d01SCy Schubert 	    (multi_ap->capability & MULTI_AP_BACKHAUL_BSS)) {
2704*a90b9d01SCy Schubert 		if (buf + len - pos < 4)
2705*a90b9d01SCy Schubert 			return 0;
2706*a90b9d01SCy Schubert 		*pos++ = MULTI_AP_VLAN_SUB_ELEM_TYPE;
2707*a90b9d01SCy Schubert 		*pos++ = 2;
2708*a90b9d01SCy Schubert 		WPA_PUT_LE16(pos, multi_ap->vlanid);
2709*a90b9d01SCy Schubert 		pos += 2;
2710*a90b9d01SCy Schubert 	}
2711*a90b9d01SCy Schubert 
2712*a90b9d01SCy Schubert 	*len_ptr = pos - len_ptr - 1;
27134bc52338SCy Schubert 
27144bc52338SCy Schubert 	return pos - buf;
27154bc52338SCy Schubert }
27164bc52338SCy Schubert 
27174bc52338SCy Schubert 
271885732ac8SCy Schubert static const struct country_op_class us_op_class[] = {
271985732ac8SCy Schubert 	{ 1, 115 },
272085732ac8SCy Schubert 	{ 2, 118 },
272185732ac8SCy Schubert 	{ 3, 124 },
272285732ac8SCy Schubert 	{ 4, 121 },
272385732ac8SCy Schubert 	{ 5, 125 },
272485732ac8SCy Schubert 	{ 12, 81 },
272585732ac8SCy Schubert 	{ 22, 116 },
272685732ac8SCy Schubert 	{ 23, 119 },
272785732ac8SCy Schubert 	{ 24, 122 },
272885732ac8SCy Schubert 	{ 25, 126 },
272985732ac8SCy Schubert 	{ 26, 126 },
273085732ac8SCy Schubert 	{ 27, 117 },
273185732ac8SCy Schubert 	{ 28, 120 },
273285732ac8SCy Schubert 	{ 29, 123 },
273385732ac8SCy Schubert 	{ 30, 127 },
273485732ac8SCy Schubert 	{ 31, 127 },
273585732ac8SCy Schubert 	{ 32, 83 },
273685732ac8SCy Schubert 	{ 33, 84 },
273785732ac8SCy Schubert 	{ 34, 180 },
273885732ac8SCy Schubert };
273985732ac8SCy Schubert 
274085732ac8SCy Schubert static const struct country_op_class eu_op_class[] = {
274185732ac8SCy Schubert 	{ 1, 115 },
274285732ac8SCy Schubert 	{ 2, 118 },
274385732ac8SCy Schubert 	{ 3, 121 },
274485732ac8SCy Schubert 	{ 4, 81 },
274585732ac8SCy Schubert 	{ 5, 116 },
274685732ac8SCy Schubert 	{ 6, 119 },
274785732ac8SCy Schubert 	{ 7, 122 },
274885732ac8SCy Schubert 	{ 8, 117 },
274985732ac8SCy Schubert 	{ 9, 120 },
275085732ac8SCy Schubert 	{ 10, 123 },
275185732ac8SCy Schubert 	{ 11, 83 },
275285732ac8SCy Schubert 	{ 12, 84 },
275385732ac8SCy Schubert 	{ 17, 125 },
275485732ac8SCy Schubert 	{ 18, 180 },
275585732ac8SCy Schubert };
275685732ac8SCy Schubert 
275785732ac8SCy Schubert static const struct country_op_class jp_op_class[] = {
275885732ac8SCy Schubert 	{ 1, 115 },
275985732ac8SCy Schubert 	{ 30, 81 },
276085732ac8SCy Schubert 	{ 31, 82 },
276185732ac8SCy Schubert 	{ 32, 118 },
276285732ac8SCy Schubert 	{ 33, 118 },
276385732ac8SCy Schubert 	{ 34, 121 },
276485732ac8SCy Schubert 	{ 35, 121 },
276585732ac8SCy Schubert 	{ 36, 116 },
276685732ac8SCy Schubert 	{ 37, 119 },
276785732ac8SCy Schubert 	{ 38, 119 },
276885732ac8SCy Schubert 	{ 39, 122 },
276985732ac8SCy Schubert 	{ 40, 122 },
277085732ac8SCy Schubert 	{ 41, 117 },
277185732ac8SCy Schubert 	{ 42, 120 },
277285732ac8SCy Schubert 	{ 43, 120 },
277385732ac8SCy Schubert 	{ 44, 123 },
277485732ac8SCy Schubert 	{ 45, 123 },
277585732ac8SCy Schubert 	{ 56, 83 },
277685732ac8SCy Schubert 	{ 57, 84 },
277785732ac8SCy Schubert 	{ 58, 121 },
277885732ac8SCy Schubert 	{ 59, 180 },
277985732ac8SCy Schubert };
278085732ac8SCy Schubert 
278185732ac8SCy Schubert static const struct country_op_class cn_op_class[] = {
278285732ac8SCy Schubert 	{ 1, 115 },
278385732ac8SCy Schubert 	{ 2, 118 },
278485732ac8SCy Schubert 	{ 3, 125 },
278585732ac8SCy Schubert 	{ 4, 116 },
278685732ac8SCy Schubert 	{ 5, 119 },
278785732ac8SCy Schubert 	{ 6, 126 },
278885732ac8SCy Schubert 	{ 7, 81 },
278985732ac8SCy Schubert 	{ 8, 83 },
279085732ac8SCy Schubert 	{ 9, 84 },
279185732ac8SCy Schubert };
279285732ac8SCy Schubert 
279385732ac8SCy Schubert static u8
global_op_class_from_country_array(u8 op_class,size_t array_size,const struct country_op_class * country_array)279485732ac8SCy Schubert global_op_class_from_country_array(u8 op_class, size_t array_size,
279585732ac8SCy Schubert 				   const struct country_op_class *country_array)
279685732ac8SCy Schubert {
279785732ac8SCy Schubert 	size_t i;
279885732ac8SCy Schubert 
279985732ac8SCy Schubert 	for (i = 0; i < array_size; i++) {
280085732ac8SCy Schubert 		if (country_array[i].country_op_class == op_class)
280185732ac8SCy Schubert 			return country_array[i].global_op_class;
280285732ac8SCy Schubert 	}
280385732ac8SCy Schubert 
280485732ac8SCy Schubert 	return 0;
280585732ac8SCy Schubert }
280685732ac8SCy Schubert 
280785732ac8SCy Schubert 
country_to_global_op_class(const char * country,u8 op_class)280885732ac8SCy Schubert u8 country_to_global_op_class(const char *country, u8 op_class)
280985732ac8SCy Schubert {
281085732ac8SCy Schubert 	const struct country_op_class *country_array;
281185732ac8SCy Schubert 	size_t size;
281285732ac8SCy Schubert 	u8 g_op_class;
281385732ac8SCy Schubert 
281485732ac8SCy Schubert 	if (country_match(us_op_class_cc, country)) {
281585732ac8SCy Schubert 		country_array = us_op_class;
281685732ac8SCy Schubert 		size = ARRAY_SIZE(us_op_class);
281785732ac8SCy Schubert 	} else if (country_match(eu_op_class_cc, country)) {
281885732ac8SCy Schubert 		country_array = eu_op_class;
281985732ac8SCy Schubert 		size = ARRAY_SIZE(eu_op_class);
282085732ac8SCy Schubert 	} else if (country_match(jp_op_class_cc, country)) {
282185732ac8SCy Schubert 		country_array = jp_op_class;
282285732ac8SCy Schubert 		size = ARRAY_SIZE(jp_op_class);
282385732ac8SCy Schubert 	} else if (country_match(cn_op_class_cc, country)) {
282485732ac8SCy Schubert 		country_array = cn_op_class;
282585732ac8SCy Schubert 		size = ARRAY_SIZE(cn_op_class);
282685732ac8SCy Schubert 	} else {
282785732ac8SCy Schubert 		/*
282885732ac8SCy Schubert 		 * Countries that do not match any of the above countries use
282985732ac8SCy Schubert 		 * global operating classes
283085732ac8SCy Schubert 		 */
283185732ac8SCy Schubert 		return op_class;
283285732ac8SCy Schubert 	}
283385732ac8SCy Schubert 
283485732ac8SCy Schubert 	g_op_class = global_op_class_from_country_array(op_class, size,
283585732ac8SCy Schubert 							country_array);
283685732ac8SCy Schubert 
283785732ac8SCy Schubert 	/*
283885732ac8SCy Schubert 	 * If the given operating class did not match any of the country's
283985732ac8SCy Schubert 	 * operating classes, assume that global operating class is used.
284085732ac8SCy Schubert 	 */
284185732ac8SCy Schubert 	return g_op_class ? g_op_class : op_class;
284285732ac8SCy Schubert }
284385732ac8SCy Schubert 
284485732ac8SCy Schubert 
get_oper_class(const char * country,u8 op_class)284585732ac8SCy Schubert const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
284685732ac8SCy Schubert {
284785732ac8SCy Schubert 	const struct oper_class_map *op;
284885732ac8SCy Schubert 
284985732ac8SCy Schubert 	if (country)
285085732ac8SCy Schubert 		op_class = country_to_global_op_class(country, op_class);
285185732ac8SCy Schubert 
285285732ac8SCy Schubert 	op = &global_op_class[0];
285385732ac8SCy Schubert 	while (op->op_class && op->op_class != op_class)
285485732ac8SCy Schubert 		op++;
285585732ac8SCy Schubert 
285685732ac8SCy Schubert 	if (!op->op_class)
285785732ac8SCy Schubert 		return NULL;
285885732ac8SCy Schubert 
285985732ac8SCy Schubert 	return op;
286085732ac8SCy Schubert }
286185732ac8SCy Schubert 
286285732ac8SCy Schubert 
oper_class_bw_to_int(const struct oper_class_map * map)28634bc52338SCy Schubert int oper_class_bw_to_int(const struct oper_class_map *map)
28644bc52338SCy Schubert {
28654bc52338SCy Schubert 	switch (map->bw) {
28664bc52338SCy Schubert 	case BW20:
28674bc52338SCy Schubert 		return 20;
2868c1d255d3SCy Schubert 	case BW40:
28694bc52338SCy Schubert 	case BW40PLUS:
28704bc52338SCy Schubert 	case BW40MINUS:
28714bc52338SCy Schubert 		return 40;
28724bc52338SCy Schubert 	case BW80:
28734bc52338SCy Schubert 		return 80;
28744bc52338SCy Schubert 	case BW80P80:
28754bc52338SCy Schubert 	case BW160:
28764bc52338SCy Schubert 		return 160;
2877*a90b9d01SCy Schubert 	case BW320:
2878*a90b9d01SCy Schubert 		return 320;
28794bc52338SCy Schubert 	case BW2160:
28804bc52338SCy Schubert 		return 2160;
28814bc52338SCy Schubert 	default:
28824bc52338SCy Schubert 		return 0;
28834bc52338SCy Schubert 	}
28844bc52338SCy Schubert }
28854bc52338SCy Schubert 
28864bc52338SCy Schubert 
center_idx_to_bw_6ghz(u8 idx)2887c1d255d3SCy Schubert int center_idx_to_bw_6ghz(u8 idx)
2888c1d255d3SCy Schubert {
2889c1d255d3SCy Schubert 	/* Channel: 2 */
2890c1d255d3SCy Schubert 	if (idx == 2)
2891c1d255d3SCy Schubert 		return 0; /* 20 MHz */
2892c1d255d3SCy Schubert 	/* channels: 1, 5, 9, 13... */
2893c1d255d3SCy Schubert 	if ((idx & 0x3) == 0x1)
2894c1d255d3SCy Schubert 		return 0; /* 20 MHz */
2895c1d255d3SCy Schubert 	/* channels 3, 11, 19... */
2896c1d255d3SCy Schubert 	if ((idx & 0x7) == 0x3)
2897c1d255d3SCy Schubert 		return 1; /* 40 MHz */
2898c1d255d3SCy Schubert 	/* channels 7, 23, 39.. */
2899c1d255d3SCy Schubert 	if ((idx & 0xf) == 0x7)
2900c1d255d3SCy Schubert 		return 2; /* 80 MHz */
2901c1d255d3SCy Schubert 	/* channels 15, 47, 79...*/
2902c1d255d3SCy Schubert 	if ((idx & 0x1f) == 0xf)
2903c1d255d3SCy Schubert 		return 3; /* 160 MHz */
2904*a90b9d01SCy Schubert 	/* channels 31, 63, 95, 127, 159, 191 */
2905*a90b9d01SCy Schubert 	if ((idx & 0x1f) == 0x1f && idx < 192)
2906*a90b9d01SCy Schubert 		return 4; /* 320 MHz */
2907c1d255d3SCy Schubert 
2908c1d255d3SCy Schubert 	return -1;
2909c1d255d3SCy Schubert }
2910c1d255d3SCy Schubert 
2911c1d255d3SCy Schubert 
is_6ghz_freq(int freq)2912c1d255d3SCy Schubert bool is_6ghz_freq(int freq)
2913c1d255d3SCy Schubert {
2914c1d255d3SCy Schubert 	if (freq < 5935 || freq > 7115)
2915c1d255d3SCy Schubert 		return false;
2916c1d255d3SCy Schubert 
2917c1d255d3SCy Schubert 	if (freq == 5935)
2918c1d255d3SCy Schubert 		return true;
2919c1d255d3SCy Schubert 
2920c1d255d3SCy Schubert 	if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
2921c1d255d3SCy Schubert 		return false;
2922c1d255d3SCy Schubert 
2923c1d255d3SCy Schubert 	return true;
2924c1d255d3SCy Schubert }
2925c1d255d3SCy Schubert 
2926c1d255d3SCy Schubert 
is_6ghz_op_class(u8 op_class)2927c1d255d3SCy Schubert bool is_6ghz_op_class(u8 op_class)
2928c1d255d3SCy Schubert {
2929*a90b9d01SCy Schubert 	return op_class >= 131 && op_class <= 137;
2930c1d255d3SCy Schubert }
2931c1d255d3SCy Schubert 
2932c1d255d3SCy Schubert 
is_6ghz_psc_frequency(int freq)2933c1d255d3SCy Schubert bool is_6ghz_psc_frequency(int freq)
2934c1d255d3SCy Schubert {
2935c1d255d3SCy Schubert 	int i;
2936c1d255d3SCy Schubert 
2937c1d255d3SCy Schubert 	if (!is_6ghz_freq(freq) || freq == 5935)
2938c1d255d3SCy Schubert 		return false;
2939c1d255d3SCy Schubert 	if ((((freq - 5950) / 5) & 0x3) != 0x1)
2940c1d255d3SCy Schubert 		return false;
2941c1d255d3SCy Schubert 
2942c1d255d3SCy Schubert 	i = (freq - 5950 + 55) % 80;
2943c1d255d3SCy Schubert 	if (i == 0)
2944c1d255d3SCy Schubert 		i = (freq - 5950 + 55) / 80;
2945c1d255d3SCy Schubert 
2946c1d255d3SCy Schubert 	if (i >= 1 && i <= 15)
2947c1d255d3SCy Schubert 		return true;
2948c1d255d3SCy Schubert 
2949c1d255d3SCy Schubert 	return false;
2950c1d255d3SCy Schubert }
2951c1d255d3SCy Schubert 
2952c1d255d3SCy Schubert 
29534b72b91aSCy Schubert /**
29544b72b91aSCy Schubert  * get_6ghz_sec_channel - Get the relative position of the secondary channel
29554b72b91aSCy Schubert  * to the primary channel in 6 GHz
29564b72b91aSCy Schubert  * @channel: Primary channel to be checked for (in global op class 131)
29574b72b91aSCy Schubert  * Returns: 1 = secondary channel above, -1 = secondary channel below
29584b72b91aSCy Schubert  */
29594b72b91aSCy Schubert 
get_6ghz_sec_channel(int channel)29604b72b91aSCy Schubert int get_6ghz_sec_channel(int channel)
29614b72b91aSCy Schubert {
29624b72b91aSCy Schubert 	/*
29634b72b91aSCy Schubert 	 * In the 6 GHz band, primary channels are numbered as 1, 5, 9, 13.., so
29644b72b91aSCy Schubert 	 * the 40 MHz channels are formed with the channel pairs as (1,5),
29654b72b91aSCy Schubert 	 * (9,13), (17,21)..
29664b72b91aSCy Schubert 	 * The secondary channel for a given primary channel is below the
29674b72b91aSCy Schubert 	 * primary channel for the channels 5, 13, 21.. and it is above the
29684b72b91aSCy Schubert 	 * primary channel for the channels 1, 9, 17..
29694b72b91aSCy Schubert 	 */
29704b72b91aSCy Schubert 
29714b72b91aSCy Schubert 	if (((channel - 1) / 4) % 2)
29724b72b91aSCy Schubert 		return -1;
29734b72b91aSCy Schubert 	return 1;
29744b72b91aSCy Schubert }
29754b72b91aSCy Schubert 
29764b72b91aSCy Schubert 
is_same_band(int freq1,int freq2)2977*a90b9d01SCy Schubert bool is_same_band(int freq1, int freq2)
2978*a90b9d01SCy Schubert {
2979*a90b9d01SCy Schubert 	if (IS_2P4GHZ(freq1) && IS_2P4GHZ(freq2))
2980*a90b9d01SCy Schubert 		return true;
2981*a90b9d01SCy Schubert 
2982*a90b9d01SCy Schubert 	if (IS_5GHZ(freq1) && IS_5GHZ(freq2))
2983*a90b9d01SCy Schubert 		return true;
2984*a90b9d01SCy Schubert 
2985*a90b9d01SCy Schubert 	if (is_6ghz_freq(freq1) && is_6ghz_freq(freq2))
2986*a90b9d01SCy Schubert 		return true;
2987*a90b9d01SCy Schubert 
2988*a90b9d01SCy Schubert 	return false;
2989*a90b9d01SCy Schubert }
2990*a90b9d01SCy Schubert 
2991*a90b9d01SCy Schubert 
ieee802_11_parse_candidate_list(const char * pos,u8 * nei_rep,size_t nei_rep_len)299285732ac8SCy Schubert int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
299385732ac8SCy Schubert 				    size_t nei_rep_len)
299485732ac8SCy Schubert {
299585732ac8SCy Schubert 	u8 *nei_pos = nei_rep;
299685732ac8SCy Schubert 	const char *end;
299785732ac8SCy Schubert 
299885732ac8SCy Schubert 	/*
299985732ac8SCy Schubert 	 * BSS Transition Candidate List Entries - Neighbor Report elements
300085732ac8SCy Schubert 	 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
300185732ac8SCy Schubert 	 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
300285732ac8SCy Schubert 	 */
300385732ac8SCy Schubert 	while (pos) {
300485732ac8SCy Schubert 		u8 *nei_start;
300585732ac8SCy Schubert 		long int val;
300685732ac8SCy Schubert 		char *endptr, *tmp;
300785732ac8SCy Schubert 
300885732ac8SCy Schubert 		pos = os_strstr(pos, " neighbor=");
300985732ac8SCy Schubert 		if (!pos)
301085732ac8SCy Schubert 			break;
301185732ac8SCy Schubert 		if (nei_pos + 15 > nei_rep + nei_rep_len) {
301285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
301385732ac8SCy Schubert 				   "Not enough room for additional neighbor");
301485732ac8SCy Schubert 			return -1;
301585732ac8SCy Schubert 		}
301685732ac8SCy Schubert 		pos += 10;
301785732ac8SCy Schubert 
301885732ac8SCy Schubert 		nei_start = nei_pos;
301985732ac8SCy Schubert 		*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
302085732ac8SCy Schubert 		nei_pos++; /* length to be filled in */
302185732ac8SCy Schubert 
302285732ac8SCy Schubert 		if (hwaddr_aton(pos, nei_pos)) {
302385732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Invalid BSSID");
302485732ac8SCy Schubert 			return -1;
302585732ac8SCy Schubert 		}
302685732ac8SCy Schubert 		nei_pos += ETH_ALEN;
302785732ac8SCy Schubert 		pos += 17;
302885732ac8SCy Schubert 		if (*pos != ',') {
302985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing BSSID Information");
303085732ac8SCy Schubert 			return -1;
303185732ac8SCy Schubert 		}
303285732ac8SCy Schubert 		pos++;
303385732ac8SCy Schubert 
303485732ac8SCy Schubert 		val = strtol(pos, &endptr, 0);
303585732ac8SCy Schubert 		WPA_PUT_LE32(nei_pos, val);
303685732ac8SCy Schubert 		nei_pos += 4;
303785732ac8SCy Schubert 		if (*endptr != ',') {
303885732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing Operating Class");
303985732ac8SCy Schubert 			return -1;
304085732ac8SCy Schubert 		}
304185732ac8SCy Schubert 		pos = endptr + 1;
304285732ac8SCy Schubert 
304385732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* Operating Class */
304485732ac8SCy Schubert 		pos = os_strchr(pos, ',');
304585732ac8SCy Schubert 		if (pos == NULL) {
304685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing Channel Number");
304785732ac8SCy Schubert 			return -1;
304885732ac8SCy Schubert 		}
304985732ac8SCy Schubert 		pos++;
305085732ac8SCy Schubert 
305185732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* Channel Number */
305285732ac8SCy Schubert 		pos = os_strchr(pos, ',');
305385732ac8SCy Schubert 		if (pos == NULL) {
305485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "Missing PHY Type");
305585732ac8SCy Schubert 			return -1;
305685732ac8SCy Schubert 		}
305785732ac8SCy Schubert 		pos++;
305885732ac8SCy Schubert 
305985732ac8SCy Schubert 		*nei_pos++ = atoi(pos); /* PHY Type */
306085732ac8SCy Schubert 		end = os_strchr(pos, ' ');
306185732ac8SCy Schubert 		tmp = os_strchr(pos, ',');
306285732ac8SCy Schubert 		if (tmp && (!end || tmp < end)) {
306385732ac8SCy Schubert 			/* Optional Subelements (hexdump) */
306485732ac8SCy Schubert 			size_t len;
306585732ac8SCy Schubert 
306685732ac8SCy Schubert 			pos = tmp + 1;
306785732ac8SCy Schubert 			end = os_strchr(pos, ' ');
306885732ac8SCy Schubert 			if (end)
306985732ac8SCy Schubert 				len = end - pos;
307085732ac8SCy Schubert 			else
307185732ac8SCy Schubert 				len = os_strlen(pos);
307285732ac8SCy Schubert 			if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
307385732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
307485732ac8SCy Schubert 					   "Not enough room for neighbor subelements");
307585732ac8SCy Schubert 				return -1;
307685732ac8SCy Schubert 			}
307785732ac8SCy Schubert 			if (len & 0x01 ||
307885732ac8SCy Schubert 			    hexstr2bin(pos, nei_pos, len / 2) < 0) {
307985732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
308085732ac8SCy Schubert 					   "Invalid neighbor subelement info");
308185732ac8SCy Schubert 				return -1;
308285732ac8SCy Schubert 			}
308385732ac8SCy Schubert 			nei_pos += len / 2;
308485732ac8SCy Schubert 			pos = end;
308585732ac8SCy Schubert 		}
308685732ac8SCy Schubert 
308785732ac8SCy Schubert 		nei_start[1] = nei_pos - nei_start - 2;
308885732ac8SCy Schubert 	}
308985732ac8SCy Schubert 
309085732ac8SCy Schubert 	return nei_pos - nei_rep;
309185732ac8SCy Schubert }
30924bc52338SCy Schubert 
30934bc52338SCy Schubert 
ieee802_11_ext_capab(const u8 * ie,unsigned int capab)30944bc52338SCy Schubert int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
30954bc52338SCy Schubert {
30964bc52338SCy Schubert 	if (!ie || ie[1] <= capab / 8)
30974bc52338SCy Schubert 		return 0;
30984bc52338SCy Schubert 	return !!(ie[2 + capab / 8] & BIT(capab % 8));
30994bc52338SCy Schubert }
3100c1d255d3SCy Schubert 
3101c1d255d3SCy Schubert 
ieee802_11_rsnx_capab_len(const u8 * rsnxe,size_t rsnxe_len,unsigned int capab)3102c1d255d3SCy Schubert bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
3103c1d255d3SCy Schubert 			       unsigned int capab)
3104c1d255d3SCy Schubert {
3105c1d255d3SCy Schubert 	const u8 *end;
3106c1d255d3SCy Schubert 	size_t flen, i;
3107c1d255d3SCy Schubert 	u32 capabs = 0;
3108c1d255d3SCy Schubert 
3109c1d255d3SCy Schubert 	if (!rsnxe || rsnxe_len == 0)
3110c1d255d3SCy Schubert 		return false;
3111c1d255d3SCy Schubert 	end = rsnxe + rsnxe_len;
3112c1d255d3SCy Schubert 	flen = (rsnxe[0] & 0x0f) + 1;
3113c1d255d3SCy Schubert 	if (rsnxe + flen > end)
3114c1d255d3SCy Schubert 		return false;
3115c1d255d3SCy Schubert 	if (flen > 4)
3116c1d255d3SCy Schubert 		flen = 4;
3117c1d255d3SCy Schubert 	for (i = 0; i < flen; i++)
3118c1d255d3SCy Schubert 		capabs |= rsnxe[i] << (8 * i);
3119c1d255d3SCy Schubert 
3120*a90b9d01SCy Schubert 	return !!(capabs & BIT(capab));
3121c1d255d3SCy Schubert }
3122c1d255d3SCy Schubert 
3123c1d255d3SCy Schubert 
ieee802_11_rsnx_capab(const u8 * rsnxe,unsigned int capab)3124c1d255d3SCy Schubert bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
3125c1d255d3SCy Schubert {
3126c1d255d3SCy Schubert 	return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL,
3127c1d255d3SCy Schubert 					 rsnxe ? rsnxe[1] : 0, capab);
3128c1d255d3SCy Schubert }
3129c1d255d3SCy Schubert 
3130c1d255d3SCy Schubert 
hostapd_encode_edmg_chan(int edmg_enable,u8 edmg_channel,int primary_channel,struct ieee80211_edmg_config * edmg)3131c1d255d3SCy Schubert void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
3132c1d255d3SCy Schubert 			      int primary_channel,
3133c1d255d3SCy Schubert 			      struct ieee80211_edmg_config *edmg)
3134c1d255d3SCy Schubert {
3135c1d255d3SCy Schubert 	if (!edmg_enable) {
3136c1d255d3SCy Schubert 		edmg->channels = 0;
3137c1d255d3SCy Schubert 		edmg->bw_config = 0;
3138c1d255d3SCy Schubert 		return;
3139c1d255d3SCy Schubert 	}
3140c1d255d3SCy Schubert 
3141c1d255d3SCy Schubert 	/* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
3142c1d255d3SCy Schubert 	switch (edmg_channel) {
3143c1d255d3SCy Schubert 	case EDMG_CHANNEL_9:
3144c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
3145c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
3146c1d255d3SCy Schubert 		return;
3147c1d255d3SCy Schubert 	case EDMG_CHANNEL_10:
3148c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
3149c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
3150c1d255d3SCy Schubert 		return;
3151c1d255d3SCy Schubert 	case EDMG_CHANNEL_11:
3152c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
3153c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
3154c1d255d3SCy Schubert 		return;
3155c1d255d3SCy Schubert 	case EDMG_CHANNEL_12:
3156c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
3157c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
3158c1d255d3SCy Schubert 		return;
3159c1d255d3SCy Schubert 	case EDMG_CHANNEL_13:
3160c1d255d3SCy Schubert 		edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
3161c1d255d3SCy Schubert 		edmg->bw_config = EDMG_BW_CONFIG_5;
3162c1d255d3SCy Schubert 		return;
3163c1d255d3SCy Schubert 	default:
3164c1d255d3SCy Schubert 		if (primary_channel > 0 && primary_channel < 7) {
3165c1d255d3SCy Schubert 			edmg->channels = BIT(primary_channel - 1);
3166c1d255d3SCy Schubert 			edmg->bw_config = EDMG_BW_CONFIG_4;
3167c1d255d3SCy Schubert 		} else {
3168c1d255d3SCy Schubert 			edmg->channels = 0;
3169c1d255d3SCy Schubert 			edmg->bw_config = 0;
3170c1d255d3SCy Schubert 		}
3171c1d255d3SCy Schubert 		break;
3172c1d255d3SCy Schubert 	}
3173c1d255d3SCy Schubert }
3174c1d255d3SCy Schubert 
3175c1d255d3SCy Schubert 
3176c1d255d3SCy Schubert /* Check if the requested EDMG configuration is a subset of the allowed
3177c1d255d3SCy Schubert  * EDMG configuration. */
ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,struct ieee80211_edmg_config requested)3178c1d255d3SCy Schubert int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
3179c1d255d3SCy Schubert 			    struct ieee80211_edmg_config requested)
3180c1d255d3SCy Schubert {
3181c1d255d3SCy Schubert 	/*
3182c1d255d3SCy Schubert 	 * The validation check if the requested EDMG configuration
3183c1d255d3SCy Schubert 	 * is a subset of the allowed EDMG configuration:
3184c1d255d3SCy Schubert 	 * 1. Check that the requested channels are part (set) of the allowed
3185c1d255d3SCy Schubert 	 * channels.
3186c1d255d3SCy Schubert 	 * 2. P802.11ay defines the values of bw_config between 4 and 15.
3187c1d255d3SCy Schubert 	 * (bw config % 4) will give us 4 groups inside bw_config definition,
3188c1d255d3SCy Schubert 	 * inside each group we can check the subset just by comparing the
3189c1d255d3SCy Schubert 	 * bw_config value.
3190c1d255d3SCy Schubert 	 * Between this 4 groups, there is no subset relation - as a result of
3191c1d255d3SCy Schubert 	 * the P802.11ay definition.
3192c1d255d3SCy Schubert 	 * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
3193c1d255d3SCy Schubert 	 */
3194c1d255d3SCy Schubert 	if (((requested.channels & allowed.channels) != requested.channels) ||
3195c1d255d3SCy Schubert 	    ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
3196c1d255d3SCy Schubert 	    requested.bw_config > allowed.bw_config)
3197c1d255d3SCy Schubert 		return 0;
3198c1d255d3SCy Schubert 
3199c1d255d3SCy Schubert 	return 1;
3200c1d255d3SCy Schubert }
3201c1d255d3SCy Schubert 
3202c1d255d3SCy Schubert 
op_class_to_bandwidth(u8 op_class)3203c1d255d3SCy Schubert int op_class_to_bandwidth(u8 op_class)
3204c1d255d3SCy Schubert {
3205c1d255d3SCy Schubert 	switch (op_class) {
3206c1d255d3SCy Schubert 	case 81:
3207c1d255d3SCy Schubert 	case 82:
3208c1d255d3SCy Schubert 		return 20;
3209c1d255d3SCy Schubert 	case 83: /* channels 1..9; 40 MHz */
3210c1d255d3SCy Schubert 	case 84: /* channels 5..13; 40 MHz */
3211c1d255d3SCy Schubert 		return 40;
3212c1d255d3SCy Schubert 	case 115: /* channels 36,40,44,48; indoor only */
3213c1d255d3SCy Schubert 		return 20;
3214c1d255d3SCy Schubert 	case 116: /* channels 36,44; 40 MHz; indoor only */
3215c1d255d3SCy Schubert 	case 117: /* channels 40,48; 40 MHz; indoor only */
3216c1d255d3SCy Schubert 		return 40;
3217c1d255d3SCy Schubert 	case 118: /* channels 52,56,60,64; dfs */
3218c1d255d3SCy Schubert 		return 20;
3219c1d255d3SCy Schubert 	case 119: /* channels 52,60; 40 MHz; dfs */
3220c1d255d3SCy Schubert 	case 120: /* channels 56,64; 40 MHz; dfs */
3221c1d255d3SCy Schubert 		return 40;
3222*a90b9d01SCy Schubert 	case 121: /* channels 100-144 */
3223c1d255d3SCy Schubert 		return 20;
3224*a90b9d01SCy Schubert 	case 122: /* channels 100-140; 40 MHz */
3225*a90b9d01SCy Schubert 	case 123: /* channels 104-144; 40 MHz */
3226c1d255d3SCy Schubert 		return 40;
3227c1d255d3SCy Schubert 	case 124: /* channels 149,153,157,161 */
3228c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,173,177 */
3229c1d255d3SCy Schubert 		return 20;
3230c1d255d3SCy Schubert 	case 126: /* channels 149,157,161,165,169,173; 40 MHz */
3231c1d255d3SCy Schubert 	case 127: /* channels 153..177; 40 MHz */
3232c1d255d3SCy Schubert 		return 40;
3233c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
3234c1d255d3SCy Schubert 		return 80;
3235c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
3236c1d255d3SCy Schubert 		return 160;
3237c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
3238c1d255d3SCy Schubert 		return 80;
3239c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
3240c1d255d3SCy Schubert 		return 20;
3241c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
3242c1d255d3SCy Schubert 		return 40;
3243c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
3244c1d255d3SCy Schubert 		return 80;
3245c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
3246c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
3247c1d255d3SCy Schubert 		return 160;
3248c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
3249c1d255d3SCy Schubert 		return 20;
3250*a90b9d01SCy Schubert 	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
3251*a90b9d01SCy Schubert 		return 320;
3252c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
3253c1d255d3SCy Schubert 		return 2160;
3254c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
3255c1d255d3SCy Schubert 		return 4320;
3256c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
3257c1d255d3SCy Schubert 		return 6480;
3258c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
3259c1d255d3SCy Schubert 		return 8640;
3260*a90b9d01SCy Schubert 	default:
3261c1d255d3SCy Schubert 		return 20;
3262c1d255d3SCy Schubert 	}
3263*a90b9d01SCy Schubert }
3264c1d255d3SCy Schubert 
3265c1d255d3SCy Schubert 
op_class_to_ch_width(u8 op_class)3266*a90b9d01SCy Schubert enum oper_chan_width op_class_to_ch_width(u8 op_class)
3267c1d255d3SCy Schubert {
3268c1d255d3SCy Schubert 	switch (op_class) {
3269c1d255d3SCy Schubert 	case 81:
3270c1d255d3SCy Schubert 	case 82:
3271*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3272c1d255d3SCy Schubert 	case 83: /* channels 1..9; 40 MHz */
3273c1d255d3SCy Schubert 	case 84: /* channels 5..13; 40 MHz */
3274*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3275c1d255d3SCy Schubert 	case 115: /* channels 36,40,44,48; indoor only */
3276*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3277c1d255d3SCy Schubert 	case 116: /* channels 36,44; 40 MHz; indoor only */
3278c1d255d3SCy Schubert 	case 117: /* channels 40,48; 40 MHz; indoor only */
3279*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3280c1d255d3SCy Schubert 	case 118: /* channels 52,56,60,64; dfs */
3281*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3282c1d255d3SCy Schubert 	case 119: /* channels 52,60; 40 MHz; dfs */
3283c1d255d3SCy Schubert 	case 120: /* channels 56,64; 40 MHz; dfs */
3284*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3285*a90b9d01SCy Schubert 	case 121: /* channels 100-144 */
3286*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3287*a90b9d01SCy Schubert 	case 122: /* channels 100-140; 40 MHz */
3288*a90b9d01SCy Schubert 	case 123: /* channels 104-144; 40 MHz */
3289*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3290c1d255d3SCy Schubert 	case 124: /* channels 149,153,157,161 */
3291c1d255d3SCy Schubert 	case 125: /* channels 149,153,157,161,165,169,171 */
3292*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3293c1d255d3SCy Schubert 	case 126: /* channels 149,157,165, 173; 40 MHz */
3294c1d255d3SCy Schubert 	case 127: /* channels 153,161,169,177; 40 MHz */
3295*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3296c1d255d3SCy Schubert 	case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
3297*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80MHZ;
3298c1d255d3SCy Schubert 	case 129: /* center freqs 50, 114, 163; 160 MHz */
3299*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_160MHZ;
3300c1d255d3SCy Schubert 	case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
3301*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80P80MHZ;
3302c1d255d3SCy Schubert 	case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
3303*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3304c1d255d3SCy Schubert 	case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
3305*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3306c1d255d3SCy Schubert 	case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
3307*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80MHZ;
3308c1d255d3SCy Schubert 	case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
3309*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_160MHZ;
3310c1d255d3SCy Schubert 	case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
3311*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80P80MHZ;
3312c1d255d3SCy Schubert 	case 136: /* UHB channels, 20 MHz: 2 */
3313*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3314*a90b9d01SCy Schubert 	case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
3315*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_320MHZ;
3316c1d255d3SCy Schubert 	case 180: /* 60 GHz band, channels 1..8 */
3317*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_2160MHZ;
3318c1d255d3SCy Schubert 	case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
3319*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_4320MHZ;
3320c1d255d3SCy Schubert 	case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
3321*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_6480MHZ;
3322c1d255d3SCy Schubert 	case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
3323*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_8640MHZ;
3324*a90b9d01SCy Schubert 	default:
3325*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3326c1d255d3SCy Schubert 	}
3327c1d255d3SCy Schubert }
3328c1d255d3SCy Schubert 
3329c1d255d3SCy Schubert 
3330*a90b9d01SCy Schubert /**
3331*a90b9d01SCy Schubert  * chwidth_freq2_to_ch_width - Determine channel width as enum oper_chan_width
3332*a90b9d01SCy Schubert  * @chwidth: Channel width integer
3333*a90b9d01SCy Schubert  * @freq2: Value for frequency 2. 0 is not used
3334*a90b9d01SCy Schubert  * Returns: enum oper_chan_width, -1 on failure
3335*a90b9d01SCy Schubert  */
chwidth_freq2_to_ch_width(int chwidth,int freq2)3336*a90b9d01SCy Schubert int chwidth_freq2_to_ch_width(int chwidth, int freq2)
3337c1d255d3SCy Schubert {
3338*a90b9d01SCy Schubert 	if (freq2 < 0)
3339*a90b9d01SCy Schubert 		return -1;
3340*a90b9d01SCy Schubert 	if (freq2)
3341*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80P80MHZ;
3342c1d255d3SCy Schubert 
3343*a90b9d01SCy Schubert 	switch (chwidth) {
3344*a90b9d01SCy Schubert 	case 0:
3345*a90b9d01SCy Schubert 	case 20:
3346*a90b9d01SCy Schubert 	case 40:
3347*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_USE_HT;
3348*a90b9d01SCy Schubert 	case 80:
3349*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_80MHZ;
3350*a90b9d01SCy Schubert 	case 160:
3351*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_160MHZ;
3352*a90b9d01SCy Schubert 	case 320:
3353*a90b9d01SCy Schubert 		return CONF_OPER_CHWIDTH_320MHZ;
3354*a90b9d01SCy Schubert 	default:
3355*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
3356*a90b9d01SCy Schubert 			   chwidth);
3357*a90b9d01SCy Schubert 		return -1;
3358*a90b9d01SCy Schubert 	}
3359*a90b9d01SCy Schubert }
3360*a90b9d01SCy Schubert 
3361*a90b9d01SCy Schubert 
ieee802_11_defrag(const u8 * data,size_t len,bool ext_elem)3362*a90b9d01SCy Schubert struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem)
3363*a90b9d01SCy Schubert {
3364*a90b9d01SCy Schubert 	struct wpabuf *buf;
3365*a90b9d01SCy Schubert 	const u8 *pos, *end = data + len;
3366*a90b9d01SCy Schubert 	size_t min_defrag_len = ext_elem ? 255 : 256;
3367*a90b9d01SCy Schubert 
3368*a90b9d01SCy Schubert 	if (!data || !len)
3369c1d255d3SCy Schubert 		return NULL;
3370c1d255d3SCy Schubert 
3371*a90b9d01SCy Schubert 	if (len < min_defrag_len)
3372*a90b9d01SCy Schubert 		return wpabuf_alloc_copy(data, len);
3373*a90b9d01SCy Schubert 
3374*a90b9d01SCy Schubert 	buf = wpabuf_alloc_copy(data, min_defrag_len - 1);
3375c1d255d3SCy Schubert 	if (!buf)
3376c1d255d3SCy Schubert 		return NULL;
3377c1d255d3SCy Schubert 
3378*a90b9d01SCy Schubert 	pos = &data[min_defrag_len - 1];
3379*a90b9d01SCy Schubert 	len -= min_defrag_len - 1;
3380*a90b9d01SCy Schubert 	while (len > 2 && pos[0] == WLAN_EID_FRAGMENT && pos[1]) {
3381c1d255d3SCy Schubert 		int ret;
3382*a90b9d01SCy Schubert 		size_t elen = 2 + pos[1];
3383c1d255d3SCy Schubert 
3384*a90b9d01SCy Schubert 		if (elen > (size_t) (end - pos) || elen > len)
3385*a90b9d01SCy Schubert 			break;
3386*a90b9d01SCy Schubert 		ret = wpabuf_resize(&buf, pos[1]);
3387c1d255d3SCy Schubert 		if (ret < 0) {
3388c1d255d3SCy Schubert 			wpabuf_free(buf);
3389c1d255d3SCy Schubert 			return NULL;
3390c1d255d3SCy Schubert 		}
3391c1d255d3SCy Schubert 
3392c1d255d3SCy Schubert 		/* Copy only the fragment data (without the EID and length) */
3393*a90b9d01SCy Schubert 		wpabuf_put_data(buf, &pos[2], pos[1]);
3394*a90b9d01SCy Schubert 		pos += elen;
3395*a90b9d01SCy Schubert 		len -= elen;
3396c1d255d3SCy Schubert 	}
3397c1d255d3SCy Schubert 
3398c1d255d3SCy Schubert 	return buf;
3399c1d255d3SCy Schubert }
3400c1d255d3SCy Schubert 
3401c1d255d3SCy Schubert 
get_ml_ie(const u8 * ies,size_t len,u8 type)3402*a90b9d01SCy Schubert const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type)
3403c1d255d3SCy Schubert {
3404*a90b9d01SCy Schubert 	const struct element *elem;
3405c1d255d3SCy Schubert 
3406*a90b9d01SCy Schubert 	if (!ies)
3407c1d255d3SCy Schubert 		return NULL;
3408*a90b9d01SCy Schubert 
3409*a90b9d01SCy Schubert 	for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, len) {
3410*a90b9d01SCy Schubert 		if (elem->datalen >= 2 &&
3411*a90b9d01SCy Schubert 		    (elem->data[1] & MULTI_LINK_CONTROL_TYPE_MASK) == type)
3412*a90b9d01SCy Schubert 			return &elem->id;
3413c1d255d3SCy Schubert 	}
3414*a90b9d01SCy Schubert 
3415c1d255d3SCy Schubert 	return NULL;
3416c1d255d3SCy Schubert }
3417c1d255d3SCy Schubert 
3418*a90b9d01SCy Schubert 
get_basic_mle_mld_addr(const u8 * buf,size_t len)3419*a90b9d01SCy Schubert const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len)
3420*a90b9d01SCy Schubert {
3421*a90b9d01SCy Schubert 	const size_t mld_addr_pos =
3422*a90b9d01SCy Schubert 		2 /* Control field */ +
3423*a90b9d01SCy Schubert 		1 /* Common Info Length field */;
3424*a90b9d01SCy Schubert 	const size_t fixed_len = mld_addr_pos +
3425*a90b9d01SCy Schubert 		ETH_ALEN /* MLD MAC Address field */;
3426*a90b9d01SCy Schubert 
3427*a90b9d01SCy Schubert 	if (len < fixed_len)
3428*a90b9d01SCy Schubert 		return NULL;
3429*a90b9d01SCy Schubert 
3430*a90b9d01SCy Schubert 	if ((buf[0] & MULTI_LINK_CONTROL_TYPE_MASK) !=
3431*a90b9d01SCy Schubert 	    MULTI_LINK_CONTROL_TYPE_BASIC)
3432*a90b9d01SCy Schubert 		return NULL;
3433*a90b9d01SCy Schubert 
3434*a90b9d01SCy Schubert 	return &buf[mld_addr_pos];
3435c1d255d3SCy Schubert }
3436