xref: /freebsd/contrib/wpa/src/common/ieee802_11_common.c (revision 78b9f0095b4af3aca6c931b2c7b009ddb8a05125)
1 /*
2  * IEEE 802.11 Common routines
3  * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "defs.h"
13 #include "wpa_common.h"
14 #include "qca-vendor.h"
15 #include "ieee802_11_defs.h"
16 #include "ieee802_11_common.h"
17 
18 
19 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
20 					    struct ieee802_11_elems *elems,
21 					    int show_errors)
22 {
23 	unsigned int oui;
24 
25 	/* first 3 bytes in vendor specific information element are the IEEE
26 	 * OUI of the vendor. The following byte is used a vendor specific
27 	 * sub-type. */
28 	if (elen < 4) {
29 		if (show_errors) {
30 			wpa_printf(MSG_MSGDUMP, "short vendor specific "
31 				   "information element ignored (len=%lu)",
32 				   (unsigned long) elen);
33 		}
34 		return -1;
35 	}
36 
37 	oui = WPA_GET_BE24(pos);
38 	switch (oui) {
39 	case OUI_MICROSOFT:
40 		/* Microsoft/Wi-Fi information elements are further typed and
41 		 * subtyped */
42 		switch (pos[3]) {
43 		case 1:
44 			/* Microsoft OUI (00:50:F2) with OUI Type 1:
45 			 * real WPA information element */
46 			elems->wpa_ie = pos;
47 			elems->wpa_ie_len = elen;
48 			break;
49 		case WMM_OUI_TYPE:
50 			/* WMM information element */
51 			if (elen < 5) {
52 				wpa_printf(MSG_MSGDUMP, "short WMM "
53 					   "information element ignored "
54 					   "(len=%lu)",
55 					   (unsigned long) elen);
56 				return -1;
57 			}
58 			switch (pos[4]) {
59 			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
60 			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
61 				/*
62 				 * Share same pointer since only one of these
63 				 * is used and they start with same data.
64 				 * Length field can be used to distinguish the
65 				 * IEs.
66 				 */
67 				elems->wmm = pos;
68 				elems->wmm_len = elen;
69 				break;
70 			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
71 				elems->wmm_tspec = pos;
72 				elems->wmm_tspec_len = elen;
73 				break;
74 			default:
75 				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
76 					   "information element ignored "
77 					   "(subtype=%d len=%lu)",
78 					   pos[4], (unsigned long) elen);
79 				return -1;
80 			}
81 			break;
82 		case 4:
83 			/* Wi-Fi Protected Setup (WPS) IE */
84 			elems->wps_ie = pos;
85 			elems->wps_ie_len = elen;
86 			break;
87 		default:
88 			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
89 				   "information element ignored "
90 				   "(type=%d len=%lu)",
91 				   pos[3], (unsigned long) elen);
92 			return -1;
93 		}
94 		break;
95 
96 	case OUI_WFA:
97 		switch (pos[3]) {
98 		case P2P_OUI_TYPE:
99 			/* Wi-Fi Alliance - P2P IE */
100 			elems->p2p = pos;
101 			elems->p2p_len = elen;
102 			break;
103 		case WFD_OUI_TYPE:
104 			/* Wi-Fi Alliance - WFD IE */
105 			elems->wfd = pos;
106 			elems->wfd_len = elen;
107 			break;
108 		case HS20_INDICATION_OUI_TYPE:
109 			/* Hotspot 2.0 */
110 			elems->hs20 = pos;
111 			elems->hs20_len = elen;
112 			break;
113 		case HS20_OSEN_OUI_TYPE:
114 			/* Hotspot 2.0 OSEN */
115 			elems->osen = pos;
116 			elems->osen_len = elen;
117 			break;
118 		case MBO_OUI_TYPE:
119 			/* MBO-OCE */
120 			elems->mbo = pos;
121 			elems->mbo_len = elen;
122 			break;
123 		default:
124 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
125 				   "information element ignored "
126 				   "(type=%d len=%lu)",
127 				   pos[3], (unsigned long) elen);
128 			return -1;
129 		}
130 		break;
131 
132 	case OUI_BROADCOM:
133 		switch (pos[3]) {
134 		case VENDOR_HT_CAPAB_OUI_TYPE:
135 			elems->vendor_ht_cap = pos;
136 			elems->vendor_ht_cap_len = elen;
137 			break;
138 		case VENDOR_VHT_TYPE:
139 			if (elen > 4 &&
140 			    (pos[4] == VENDOR_VHT_SUBTYPE ||
141 			     pos[4] == VENDOR_VHT_SUBTYPE2)) {
142 				elems->vendor_vht = pos;
143 				elems->vendor_vht_len = elen;
144 			} else
145 				return -1;
146 			break;
147 		default:
148 			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
149 				   "information element ignored "
150 				   "(type=%d len=%lu)",
151 				   pos[3], (unsigned long) elen);
152 			return -1;
153 		}
154 		break;
155 
156 	case OUI_QCA:
157 		switch (pos[3]) {
158 		case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
159 			elems->pref_freq_list = pos;
160 			elems->pref_freq_list_len = elen;
161 			break;
162 		default:
163 			wpa_printf(MSG_EXCESSIVE,
164 				   "Unknown QCA information element ignored (type=%d len=%lu)",
165 				   pos[3], (unsigned long) elen);
166 			return -1;
167 		}
168 		break;
169 
170 	default:
171 		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
172 			   "information element ignored (vendor OUI "
173 			   "%02x:%02x:%02x len=%lu)",
174 			   pos[0], pos[1], pos[2], (unsigned long) elen);
175 		return -1;
176 	}
177 
178 	return 0;
179 }
180 
181 
182 /**
183  * ieee802_11_parse_elems - Parse information elements in management frames
184  * @start: Pointer to the start of IEs
185  * @len: Length of IE buffer in octets
186  * @elems: Data structure for parsed elements
187  * @show_errors: Whether to show parsing errors in debug log
188  * Returns: Parsing result
189  */
190 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
191 				struct ieee802_11_elems *elems,
192 				int show_errors)
193 {
194 	size_t left = len;
195 	const u8 *pos = start;
196 	int unknown = 0;
197 
198 	os_memset(elems, 0, sizeof(*elems));
199 
200 	while (left >= 2) {
201 		u8 id, elen;
202 
203 		id = *pos++;
204 		elen = *pos++;
205 		left -= 2;
206 
207 		if (elen > left) {
208 			if (show_errors) {
209 				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
210 					   "parse failed (id=%d elen=%d "
211 					   "left=%lu)",
212 					   id, elen, (unsigned long) left);
213 				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
214 			}
215 			return ParseFailed;
216 		}
217 
218 		switch (id) {
219 		case WLAN_EID_SSID:
220 			if (elen > SSID_MAX_LEN) {
221 				wpa_printf(MSG_DEBUG,
222 					   "Ignored too long SSID element (elen=%u)",
223 					   elen);
224 				break;
225 			}
226 			elems->ssid = pos;
227 			elems->ssid_len = elen;
228 			break;
229 		case WLAN_EID_SUPP_RATES:
230 			elems->supp_rates = pos;
231 			elems->supp_rates_len = elen;
232 			break;
233 		case WLAN_EID_DS_PARAMS:
234 			if (elen < 1)
235 				break;
236 			elems->ds_params = pos;
237 			break;
238 		case WLAN_EID_CF_PARAMS:
239 		case WLAN_EID_TIM:
240 			break;
241 		case WLAN_EID_CHALLENGE:
242 			elems->challenge = pos;
243 			elems->challenge_len = elen;
244 			break;
245 		case WLAN_EID_ERP_INFO:
246 			if (elen < 1)
247 				break;
248 			elems->erp_info = pos;
249 			break;
250 		case WLAN_EID_EXT_SUPP_RATES:
251 			elems->ext_supp_rates = pos;
252 			elems->ext_supp_rates_len = elen;
253 			break;
254 		case WLAN_EID_VENDOR_SPECIFIC:
255 			if (ieee802_11_parse_vendor_specific(pos, elen,
256 							     elems,
257 							     show_errors))
258 				unknown++;
259 			break;
260 		case WLAN_EID_RSN:
261 			elems->rsn_ie = pos;
262 			elems->rsn_ie_len = elen;
263 			break;
264 		case WLAN_EID_PWR_CAPABILITY:
265 			break;
266 		case WLAN_EID_SUPPORTED_CHANNELS:
267 			elems->supp_channels = pos;
268 			elems->supp_channels_len = elen;
269 			break;
270 		case WLAN_EID_MOBILITY_DOMAIN:
271 			if (elen < sizeof(struct rsn_mdie))
272 				break;
273 			elems->mdie = pos;
274 			elems->mdie_len = elen;
275 			break;
276 		case WLAN_EID_FAST_BSS_TRANSITION:
277 			if (elen < sizeof(struct rsn_ftie))
278 				break;
279 			elems->ftie = pos;
280 			elems->ftie_len = elen;
281 			break;
282 		case WLAN_EID_TIMEOUT_INTERVAL:
283 			if (elen != 5)
284 				break;
285 			elems->timeout_int = pos;
286 			break;
287 		case WLAN_EID_HT_CAP:
288 			if (elen < sizeof(struct ieee80211_ht_capabilities))
289 				break;
290 			elems->ht_capabilities = pos;
291 			break;
292 		case WLAN_EID_HT_OPERATION:
293 			if (elen < sizeof(struct ieee80211_ht_operation))
294 				break;
295 			elems->ht_operation = pos;
296 			break;
297 		case WLAN_EID_MESH_CONFIG:
298 			elems->mesh_config = pos;
299 			elems->mesh_config_len = elen;
300 			break;
301 		case WLAN_EID_MESH_ID:
302 			elems->mesh_id = pos;
303 			elems->mesh_id_len = elen;
304 			break;
305 		case WLAN_EID_PEER_MGMT:
306 			elems->peer_mgmt = pos;
307 			elems->peer_mgmt_len = elen;
308 			break;
309 		case WLAN_EID_VHT_CAP:
310 			if (elen < sizeof(struct ieee80211_vht_capabilities))
311 				break;
312 			elems->vht_capabilities = pos;
313 			break;
314 		case WLAN_EID_VHT_OPERATION:
315 			if (elen < sizeof(struct ieee80211_vht_operation))
316 				break;
317 			elems->vht_operation = pos;
318 			break;
319 		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
320 			if (elen != 1)
321 				break;
322 			elems->vht_opmode_notif = pos;
323 			break;
324 		case WLAN_EID_LINK_ID:
325 			if (elen < 18)
326 				break;
327 			elems->link_id = pos;
328 			break;
329 		case WLAN_EID_INTERWORKING:
330 			elems->interworking = pos;
331 			elems->interworking_len = elen;
332 			break;
333 		case WLAN_EID_QOS_MAP_SET:
334 			if (elen < 16)
335 				break;
336 			elems->qos_map_set = pos;
337 			elems->qos_map_set_len = elen;
338 			break;
339 		case WLAN_EID_EXT_CAPAB:
340 			elems->ext_capab = pos;
341 			elems->ext_capab_len = elen;
342 			break;
343 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
344 			if (elen < 3)
345 				break;
346 			elems->bss_max_idle_period = pos;
347 			break;
348 		case WLAN_EID_SSID_LIST:
349 			elems->ssid_list = pos;
350 			elems->ssid_list_len = elen;
351 			break;
352 		case WLAN_EID_AMPE:
353 			elems->ampe = pos;
354 			elems->ampe_len = elen;
355 			break;
356 		case WLAN_EID_MIC:
357 			elems->mic = pos;
358 			elems->mic_len = elen;
359 			/* after mic everything is encrypted, so stop. */
360 			left = elen;
361 			break;
362 		case WLAN_EID_MULTI_BAND:
363 			if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
364 				wpa_printf(MSG_MSGDUMP,
365 					   "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
366 					   id, elen);
367 				break;
368 			}
369 
370 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
371 			elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
372 			elems->mb_ies.nof_ies++;
373 			break;
374 		case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
375 			elems->supp_op_classes = pos;
376 			elems->supp_op_classes_len = elen;
377 			break;
378 		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
379 			elems->rrm_enabled = pos;
380 			elems->rrm_enabled_len = elen;
381 			break;
382 		default:
383 			unknown++;
384 			if (!show_errors)
385 				break;
386 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
387 				   "ignored unknown element (id=%d elen=%d)",
388 				   id, elen);
389 			break;
390 		}
391 
392 		left -= elen;
393 		pos += elen;
394 	}
395 
396 	if (left)
397 		return ParseFailed;
398 
399 	return unknown ? ParseUnknown : ParseOK;
400 }
401 
402 
403 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
404 {
405 	int count = 0;
406 	const u8 *pos, *end;
407 
408 	if (ies == NULL)
409 		return 0;
410 
411 	pos = ies;
412 	end = ies + ies_len;
413 
414 	while (end - pos >= 2) {
415 		if (2 + pos[1] > end - pos)
416 			break;
417 		count++;
418 		pos += 2 + pos[1];
419 	}
420 
421 	return count;
422 }
423 
424 
425 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
426 					    u32 oui_type)
427 {
428 	struct wpabuf *buf;
429 	const u8 *end, *pos, *ie;
430 
431 	pos = ies;
432 	end = ies + ies_len;
433 	ie = NULL;
434 
435 	while (end - pos > 1) {
436 		if (2 + pos[1] > end - pos)
437 			return NULL;
438 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
439 		    WPA_GET_BE32(&pos[2]) == oui_type) {
440 			ie = pos;
441 			break;
442 		}
443 		pos += 2 + pos[1];
444 	}
445 
446 	if (ie == NULL)
447 		return NULL; /* No specified vendor IE found */
448 
449 	buf = wpabuf_alloc(ies_len);
450 	if (buf == NULL)
451 		return NULL;
452 
453 	/*
454 	 * There may be multiple vendor IEs in the message, so need to
455 	 * concatenate their data fields.
456 	 */
457 	while (end - pos > 1) {
458 		if (2 + pos[1] > end - pos)
459 			break;
460 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
461 		    WPA_GET_BE32(&pos[2]) == oui_type)
462 			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
463 		pos += 2 + pos[1];
464 	}
465 
466 	return buf;
467 }
468 
469 
470 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
471 {
472 	u16 fc, type, stype;
473 
474 	/*
475 	 * PS-Poll frames are 16 bytes. All other frames are
476 	 * 24 bytes or longer.
477 	 */
478 	if (len < 16)
479 		return NULL;
480 
481 	fc = le_to_host16(hdr->frame_control);
482 	type = WLAN_FC_GET_TYPE(fc);
483 	stype = WLAN_FC_GET_STYPE(fc);
484 
485 	switch (type) {
486 	case WLAN_FC_TYPE_DATA:
487 		if (len < 24)
488 			return NULL;
489 		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
490 		case WLAN_FC_FROMDS | WLAN_FC_TODS:
491 		case WLAN_FC_TODS:
492 			return hdr->addr1;
493 		case WLAN_FC_FROMDS:
494 			return hdr->addr2;
495 		default:
496 			return NULL;
497 		}
498 	case WLAN_FC_TYPE_CTRL:
499 		if (stype != WLAN_FC_STYPE_PSPOLL)
500 			return NULL;
501 		return hdr->addr1;
502 	case WLAN_FC_TYPE_MGMT:
503 		return hdr->addr3;
504 	default:
505 		return NULL;
506 	}
507 }
508 
509 
510 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
511 			  const char *name, const char *val)
512 {
513 	int num, v;
514 	const char *pos;
515 	struct hostapd_wmm_ac_params *ac;
516 
517 	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
518 	pos = name + 7;
519 	if (os_strncmp(pos, "be_", 3) == 0) {
520 		num = 0;
521 		pos += 3;
522 	} else if (os_strncmp(pos, "bk_", 3) == 0) {
523 		num = 1;
524 		pos += 3;
525 	} else if (os_strncmp(pos, "vi_", 3) == 0) {
526 		num = 2;
527 		pos += 3;
528 	} else if (os_strncmp(pos, "vo_", 3) == 0) {
529 		num = 3;
530 		pos += 3;
531 	} else {
532 		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
533 		return -1;
534 	}
535 
536 	ac = &wmm_ac_params[num];
537 
538 	if (os_strcmp(pos, "aifs") == 0) {
539 		v = atoi(val);
540 		if (v < 1 || v > 255) {
541 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
542 			return -1;
543 		}
544 		ac->aifs = v;
545 	} else if (os_strcmp(pos, "cwmin") == 0) {
546 		v = atoi(val);
547 		if (v < 0 || v > 15) {
548 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
549 			return -1;
550 		}
551 		ac->cwmin = v;
552 	} else if (os_strcmp(pos, "cwmax") == 0) {
553 		v = atoi(val);
554 		if (v < 0 || v > 15) {
555 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
556 			return -1;
557 		}
558 		ac->cwmax = v;
559 	} else if (os_strcmp(pos, "txop_limit") == 0) {
560 		v = atoi(val);
561 		if (v < 0 || v > 0xffff) {
562 			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
563 			return -1;
564 		}
565 		ac->txop_limit = v;
566 	} else if (os_strcmp(pos, "acm") == 0) {
567 		v = atoi(val);
568 		if (v < 0 || v > 1) {
569 			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
570 			return -1;
571 		}
572 		ac->admission_control_mandatory = v;
573 	} else {
574 		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
575 		return -1;
576 	}
577 
578 	return 0;
579 }
580 
581 
582 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
583 {
584 	u8 op_class;
585 
586 	return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
587 					     &op_class, channel);
588 }
589 
590 
591 /**
592  * ieee80211_freq_to_channel_ext - Convert frequency into channel info
593  * for HT40 and VHT. DFS channels are not covered.
594  * @freq: Frequency (MHz) to convert
595  * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
596  * @vht: VHT channel width (VHT_CHANWIDTH_*)
597  * @op_class: Buffer for returning operating class
598  * @channel: Buffer for returning channel number
599  * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
600  */
601 enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
602 						   int sec_channel, int vht,
603 						   u8 *op_class, u8 *channel)
604 {
605 	u8 vht_opclass;
606 
607 	/* TODO: more operating classes */
608 
609 	if (sec_channel > 1 || sec_channel < -1)
610 		return NUM_HOSTAPD_MODES;
611 
612 	if (freq >= 2412 && freq <= 2472) {
613 		if ((freq - 2407) % 5)
614 			return NUM_HOSTAPD_MODES;
615 
616 		if (vht)
617 			return NUM_HOSTAPD_MODES;
618 
619 		/* 2.407 GHz, channels 1..13 */
620 		if (sec_channel == 1)
621 			*op_class = 83;
622 		else if (sec_channel == -1)
623 			*op_class = 84;
624 		else
625 			*op_class = 81;
626 
627 		*channel = (freq - 2407) / 5;
628 
629 		return HOSTAPD_MODE_IEEE80211G;
630 	}
631 
632 	if (freq == 2484) {
633 		if (sec_channel || vht)
634 			return NUM_HOSTAPD_MODES;
635 
636 		*op_class = 82; /* channel 14 */
637 		*channel = 14;
638 
639 		return HOSTAPD_MODE_IEEE80211B;
640 	}
641 
642 	if (freq >= 4900 && freq < 5000) {
643 		if ((freq - 4000) % 5)
644 			return NUM_HOSTAPD_MODES;
645 		*channel = (freq - 4000) / 5;
646 		*op_class = 0; /* TODO */
647 		return HOSTAPD_MODE_IEEE80211A;
648 	}
649 
650 	switch (vht) {
651 	case VHT_CHANWIDTH_80MHZ:
652 		vht_opclass = 128;
653 		break;
654 	case VHT_CHANWIDTH_160MHZ:
655 		vht_opclass = 129;
656 		break;
657 	case VHT_CHANWIDTH_80P80MHZ:
658 		vht_opclass = 130;
659 		break;
660 	default:
661 		vht_opclass = 0;
662 		break;
663 	}
664 
665 	/* 5 GHz, channels 36..48 */
666 	if (freq >= 5180 && freq <= 5240) {
667 		if ((freq - 5000) % 5)
668 			return NUM_HOSTAPD_MODES;
669 
670 		if (vht_opclass)
671 			*op_class = vht_opclass;
672 		else if (sec_channel == 1)
673 			*op_class = 116;
674 		else if (sec_channel == -1)
675 			*op_class = 117;
676 		else
677 			*op_class = 115;
678 
679 		*channel = (freq - 5000) / 5;
680 
681 		return HOSTAPD_MODE_IEEE80211A;
682 	}
683 
684 	/* 5 GHz, channels 149..169 */
685 	if (freq >= 5745 && freq <= 5845) {
686 		if ((freq - 5000) % 5)
687 			return NUM_HOSTAPD_MODES;
688 
689 		if (vht_opclass)
690 			*op_class = vht_opclass;
691 		else if (sec_channel == 1)
692 			*op_class = 126;
693 		else if (sec_channel == -1)
694 			*op_class = 127;
695 		else if (freq <= 5805)
696 			*op_class = 124;
697 		else
698 			*op_class = 125;
699 
700 		*channel = (freq - 5000) / 5;
701 
702 		return HOSTAPD_MODE_IEEE80211A;
703 	}
704 
705 	/* 5 GHz, channels 100..140 */
706 	if (freq >= 5000 && freq <= 5700) {
707 		if ((freq - 5000) % 5)
708 			return NUM_HOSTAPD_MODES;
709 
710 		if (vht_opclass)
711 			*op_class = vht_opclass;
712 		else if (sec_channel == 1)
713 			*op_class = 122;
714 		else if (sec_channel == -1)
715 			*op_class = 123;
716 		else
717 			*op_class = 121;
718 
719 		*channel = (freq - 5000) / 5;
720 
721 		return HOSTAPD_MODE_IEEE80211A;
722 	}
723 
724 	if (freq >= 5000 && freq < 5900) {
725 		if ((freq - 5000) % 5)
726 			return NUM_HOSTAPD_MODES;
727 		*channel = (freq - 5000) / 5;
728 		*op_class = 0; /* TODO */
729 		return HOSTAPD_MODE_IEEE80211A;
730 	}
731 
732 	/* 56.16 GHz, channel 1..4 */
733 	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
734 		if (sec_channel || vht)
735 			return NUM_HOSTAPD_MODES;
736 
737 		*channel = (freq - 56160) / 2160;
738 		*op_class = 180;
739 
740 		return HOSTAPD_MODE_IEEE80211AD;
741 	}
742 
743 	return NUM_HOSTAPD_MODES;
744 }
745 
746 
747 static const char *const us_op_class_cc[] = {
748 	"US", "CA", NULL
749 };
750 
751 static const char *const eu_op_class_cc[] = {
752 	"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
753 	"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
754 	"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
755 	"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
756 };
757 
758 static const char *const jp_op_class_cc[] = {
759 	"JP", NULL
760 };
761 
762 static const char *const cn_op_class_cc[] = {
763 	"CN", NULL
764 };
765 
766 
767 static int country_match(const char *const cc[], const char *const country)
768 {
769 	int i;
770 
771 	if (country == NULL)
772 		return 0;
773 	for (i = 0; cc[i]; i++) {
774 		if (cc[i][0] == country[0] && cc[i][1] == country[1])
775 			return 1;
776 	}
777 
778 	return 0;
779 }
780 
781 
782 static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
783 {
784 	switch (op_class) {
785 	case 12: /* channels 1..11 */
786 	case 32: /* channels 1..7; 40 MHz */
787 	case 33: /* channels 5..11; 40 MHz */
788 		if (chan < 1 || chan > 11)
789 			return -1;
790 		return 2407 + 5 * chan;
791 	case 1: /* channels 36,40,44,48 */
792 	case 2: /* channels 52,56,60,64; dfs */
793 	case 22: /* channels 36,44; 40 MHz */
794 	case 23: /* channels 52,60; 40 MHz */
795 	case 27: /* channels 40,48; 40 MHz */
796 	case 28: /* channels 56,64; 40 MHz */
797 		if (chan < 36 || chan > 64)
798 			return -1;
799 		return 5000 + 5 * chan;
800 	case 4: /* channels 100-144 */
801 	case 24: /* channels 100-140; 40 MHz */
802 		if (chan < 100 || chan > 144)
803 			return -1;
804 		return 5000 + 5 * chan;
805 	case 3: /* channels 149,153,157,161 */
806 	case 25: /* channels 149,157; 40 MHz */
807 	case 26: /* channels 149,157; 40 MHz */
808 	case 30: /* channels 153,161; 40 MHz */
809 	case 31: /* channels 153,161; 40 MHz */
810 		if (chan < 149 || chan > 161)
811 			return -1;
812 		return 5000 + 5 * chan;
813 	case 5: /* channels 149,153,157,161,165 */
814 		if (chan < 149 || chan > 165)
815 			return -1;
816 		return 5000 + 5 * chan;
817 	case 34: /* 60 GHz band, channels 1..3 */
818 		if (chan < 1 || chan > 3)
819 			return -1;
820 		return 56160 + 2160 * chan;
821 	}
822 	return -1;
823 }
824 
825 
826 static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
827 {
828 	switch (op_class) {
829 	case 4: /* channels 1..13 */
830 	case 11: /* channels 1..9; 40 MHz */
831 	case 12: /* channels 5..13; 40 MHz */
832 		if (chan < 1 || chan > 13)
833 			return -1;
834 		return 2407 + 5 * chan;
835 	case 1: /* channels 36,40,44,48 */
836 	case 2: /* channels 52,56,60,64; dfs */
837 	case 5: /* channels 36,44; 40 MHz */
838 	case 6: /* channels 52,60; 40 MHz */
839 	case 8: /* channels 40,48; 40 MHz */
840 	case 9: /* channels 56,64; 40 MHz */
841 		if (chan < 36 || chan > 64)
842 			return -1;
843 		return 5000 + 5 * chan;
844 	case 3: /* channels 100-140 */
845 	case 7: /* channels 100-132; 40 MHz */
846 	case 10: /* channels 104-136; 40 MHz */
847 	case 16: /* channels 100-140 */
848 		if (chan < 100 || chan > 140)
849 			return -1;
850 		return 5000 + 5 * chan;
851 	case 17: /* channels 149,153,157,161,165,169 */
852 		if (chan < 149 || chan > 169)
853 			return -1;
854 		return 5000 + 5 * chan;
855 	case 18: /* 60 GHz band, channels 1..4 */
856 		if (chan < 1 || chan > 4)
857 			return -1;
858 		return 56160 + 2160 * chan;
859 	}
860 	return -1;
861 }
862 
863 
864 static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
865 {
866 	switch (op_class) {
867 	case 30: /* channels 1..13 */
868 	case 56: /* channels 1..9; 40 MHz */
869 	case 57: /* channels 5..13; 40 MHz */
870 		if (chan < 1 || chan > 13)
871 			return -1;
872 		return 2407 + 5 * chan;
873 	case 31: /* channel 14 */
874 		if (chan != 14)
875 			return -1;
876 		return 2414 + 5 * chan;
877 	case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
878 	case 32: /* channels 52,56,60,64 */
879 	case 33: /* channels 52,56,60,64 */
880 	case 36: /* channels 36,44; 40 MHz */
881 	case 37: /* channels 52,60; 40 MHz */
882 	case 38: /* channels 52,60; 40 MHz */
883 	case 41: /* channels 40,48; 40 MHz */
884 	case 42: /* channels 56,64; 40 MHz */
885 	case 43: /* channels 56,64; 40 MHz */
886 		if (chan < 34 || chan > 64)
887 			return -1;
888 		return 5000 + 5 * chan;
889 	case 34: /* channels 100-140 */
890 	case 35: /* channels 100-140 */
891 	case 39: /* channels 100-132; 40 MHz */
892 	case 40: /* channels 100-132; 40 MHz */
893 	case 44: /* channels 104-136; 40 MHz */
894 	case 45: /* channels 104-136; 40 MHz */
895 	case 58: /* channels 100-140 */
896 		if (chan < 100 || chan > 140)
897 			return -1;
898 		return 5000 + 5 * chan;
899 	case 59: /* 60 GHz band, channels 1..4 */
900 		if (chan < 1 || chan > 3)
901 			return -1;
902 		return 56160 + 2160 * chan;
903 	}
904 	return -1;
905 }
906 
907 
908 static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
909 {
910 	switch (op_class) {
911 	case 7: /* channels 1..13 */
912 	case 8: /* channels 1..9; 40 MHz */
913 	case 9: /* channels 5..13; 40 MHz */
914 		if (chan < 1 || chan > 13)
915 			return -1;
916 		return 2407 + 5 * chan;
917 	case 1: /* channels 36,40,44,48 */
918 	case 2: /* channels 52,56,60,64; dfs */
919 	case 4: /* channels 36,44; 40 MHz */
920 	case 5: /* channels 52,60; 40 MHz */
921 		if (chan < 36 || chan > 64)
922 			return -1;
923 		return 5000 + 5 * chan;
924 	case 3: /* channels 149,153,157,161,165 */
925 	case 6: /* channels 149,157; 40 MHz */
926 		if (chan < 149 || chan > 165)
927 			return -1;
928 		return 5000 + 5 * chan;
929 	}
930 	return -1;
931 }
932 
933 
934 static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
935 {
936 	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
937 	switch (op_class) {
938 	case 81:
939 		/* channels 1..13 */
940 		if (chan < 1 || chan > 13)
941 			return -1;
942 		return 2407 + 5 * chan;
943 	case 82:
944 		/* channel 14 */
945 		if (chan != 14)
946 			return -1;
947 		return 2414 + 5 * chan;
948 	case 83: /* channels 1..9; 40 MHz */
949 	case 84: /* channels 5..13; 40 MHz */
950 		if (chan < 1 || chan > 13)
951 			return -1;
952 		return 2407 + 5 * chan;
953 	case 115: /* channels 36,40,44,48; indoor only */
954 	case 116: /* channels 36,44; 40 MHz; indoor only */
955 	case 117: /* channels 40,48; 40 MHz; indoor only */
956 	case 118: /* channels 52,56,60,64; dfs */
957 	case 119: /* channels 52,60; 40 MHz; dfs */
958 	case 120: /* channels 56,64; 40 MHz; dfs */
959 		if (chan < 36 || chan > 64)
960 			return -1;
961 		return 5000 + 5 * chan;
962 	case 121: /* channels 100-140 */
963 	case 122: /* channels 100-142; 40 MHz */
964 	case 123: /* channels 104-136; 40 MHz */
965 		if (chan < 100 || chan > 140)
966 			return -1;
967 		return 5000 + 5 * chan;
968 	case 124: /* channels 149,153,157,161 */
969 	case 126: /* channels 149,157; 40 MHz */
970 	case 127: /* channels 153,161; 40 MHz */
971 		if (chan < 149 || chan > 161)
972 			return -1;
973 		return 5000 + 5 * chan;
974 	case 125: /* channels 149,153,157,161,165,169 */
975 		if (chan < 149 || chan > 169)
976 			return -1;
977 		return 5000 + 5 * chan;
978 	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
979 	case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
980 		if (chan < 36 || chan > 161)
981 			return -1;
982 		return 5000 + 5 * chan;
983 	case 129: /* center freqs 50, 114; 160 MHz */
984 		if (chan < 50 || chan > 114)
985 			return -1;
986 		return 5000 + 5 * chan;
987 	case 180: /* 60 GHz band, channels 1..4 */
988 		if (chan < 1 || chan > 4)
989 			return -1;
990 		return 56160 + 2160 * chan;
991 	}
992 	return -1;
993 }
994 
995 /**
996  * ieee80211_chan_to_freq - Convert channel info to frequency
997  * @country: Country code, if known; otherwise, global operating class is used
998  * @op_class: Operating class
999  * @chan: Channel number
1000  * Returns: Frequency in MHz or -1 if the specified channel is unknown
1001  */
1002 int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
1003 {
1004 	int freq;
1005 
1006 	if (country_match(us_op_class_cc, country)) {
1007 		freq = ieee80211_chan_to_freq_us(op_class, chan);
1008 		if (freq > 0)
1009 			return freq;
1010 	}
1011 
1012 	if (country_match(eu_op_class_cc, country)) {
1013 		freq = ieee80211_chan_to_freq_eu(op_class, chan);
1014 		if (freq > 0)
1015 			return freq;
1016 	}
1017 
1018 	if (country_match(jp_op_class_cc, country)) {
1019 		freq = ieee80211_chan_to_freq_jp(op_class, chan);
1020 		if (freq > 0)
1021 			return freq;
1022 	}
1023 
1024 	if (country_match(cn_op_class_cc, country)) {
1025 		freq = ieee80211_chan_to_freq_cn(op_class, chan);
1026 		if (freq > 0)
1027 			return freq;
1028 	}
1029 
1030 	return ieee80211_chan_to_freq_global(op_class, chan);
1031 }
1032 
1033 
1034 int ieee80211_is_dfs(int freq)
1035 {
1036 	/* TODO: this could be more accurate to better cover all domains */
1037 	return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
1038 }
1039 
1040 
1041 static int is_11b(u8 rate)
1042 {
1043 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
1044 }
1045 
1046 
1047 int supp_rates_11b_only(struct ieee802_11_elems *elems)
1048 {
1049 	int num_11b = 0, num_others = 0;
1050 	int i;
1051 
1052 	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
1053 		return 0;
1054 
1055 	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
1056 		if (is_11b(elems->supp_rates[i]))
1057 			num_11b++;
1058 		else
1059 			num_others++;
1060 	}
1061 
1062 	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
1063 	     i++) {
1064 		if (is_11b(elems->ext_supp_rates[i]))
1065 			num_11b++;
1066 		else
1067 			num_others++;
1068 	}
1069 
1070 	return num_11b > 0 && num_others == 0;
1071 }
1072 
1073 
1074 const char * fc2str(u16 fc)
1075 {
1076 	u16 stype = WLAN_FC_GET_STYPE(fc);
1077 #define C2S(x) case x: return #x;
1078 
1079 	switch (WLAN_FC_GET_TYPE(fc)) {
1080 	case WLAN_FC_TYPE_MGMT:
1081 		switch (stype) {
1082 		C2S(WLAN_FC_STYPE_ASSOC_REQ)
1083 		C2S(WLAN_FC_STYPE_ASSOC_RESP)
1084 		C2S(WLAN_FC_STYPE_REASSOC_REQ)
1085 		C2S(WLAN_FC_STYPE_REASSOC_RESP)
1086 		C2S(WLAN_FC_STYPE_PROBE_REQ)
1087 		C2S(WLAN_FC_STYPE_PROBE_RESP)
1088 		C2S(WLAN_FC_STYPE_BEACON)
1089 		C2S(WLAN_FC_STYPE_ATIM)
1090 		C2S(WLAN_FC_STYPE_DISASSOC)
1091 		C2S(WLAN_FC_STYPE_AUTH)
1092 		C2S(WLAN_FC_STYPE_DEAUTH)
1093 		C2S(WLAN_FC_STYPE_ACTION)
1094 		}
1095 		break;
1096 	case WLAN_FC_TYPE_CTRL:
1097 		switch (stype) {
1098 		C2S(WLAN_FC_STYPE_PSPOLL)
1099 		C2S(WLAN_FC_STYPE_RTS)
1100 		C2S(WLAN_FC_STYPE_CTS)
1101 		C2S(WLAN_FC_STYPE_ACK)
1102 		C2S(WLAN_FC_STYPE_CFEND)
1103 		C2S(WLAN_FC_STYPE_CFENDACK)
1104 		}
1105 		break;
1106 	case WLAN_FC_TYPE_DATA:
1107 		switch (stype) {
1108 		C2S(WLAN_FC_STYPE_DATA)
1109 		C2S(WLAN_FC_STYPE_DATA_CFACK)
1110 		C2S(WLAN_FC_STYPE_DATA_CFPOLL)
1111 		C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
1112 		C2S(WLAN_FC_STYPE_NULLFUNC)
1113 		C2S(WLAN_FC_STYPE_CFACK)
1114 		C2S(WLAN_FC_STYPE_CFPOLL)
1115 		C2S(WLAN_FC_STYPE_CFACKPOLL)
1116 		C2S(WLAN_FC_STYPE_QOS_DATA)
1117 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
1118 		C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
1119 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
1120 		C2S(WLAN_FC_STYPE_QOS_NULL)
1121 		C2S(WLAN_FC_STYPE_QOS_CFPOLL)
1122 		C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
1123 		}
1124 		break;
1125 	}
1126 	return "WLAN_FC_TYPE_UNKNOWN";
1127 #undef C2S
1128 }
1129 
1130 
1131 int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
1132 		       size_t ies_len)
1133 {
1134 	os_memset(info, 0, sizeof(*info));
1135 
1136 	while (ies_buf && ies_len >= 2 &&
1137 	       info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
1138 		size_t len = 2 + ies_buf[1];
1139 
1140 		if (len > ies_len) {
1141 			wpa_hexdump(MSG_DEBUG, "Truncated IEs",
1142 				    ies_buf, ies_len);
1143 			return -1;
1144 		}
1145 
1146 		if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
1147 			wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
1148 			info->ies[info->nof_ies].ie = ies_buf + 2;
1149 			info->ies[info->nof_ies].ie_len = ies_buf[1];
1150 			info->nof_ies++;
1151 		}
1152 
1153 		ies_len -= len;
1154 		ies_buf += len;
1155 	}
1156 
1157 	return 0;
1158 }
1159 
1160 
1161 struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
1162 {
1163 	struct wpabuf *mb_ies = NULL;
1164 
1165 	WPA_ASSERT(info != NULL);
1166 
1167 	if (info->nof_ies) {
1168 		u8 i;
1169 		size_t mb_ies_size = 0;
1170 
1171 		for (i = 0; i < info->nof_ies; i++)
1172 			mb_ies_size += 2 + info->ies[i].ie_len;
1173 
1174 		mb_ies = wpabuf_alloc(mb_ies_size);
1175 		if (mb_ies) {
1176 			for (i = 0; i < info->nof_ies; i++) {
1177 				wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
1178 				wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
1179 				wpabuf_put_data(mb_ies,
1180 						info->ies[i].ie,
1181 						info->ies[i].ie_len);
1182 			}
1183 		}
1184 	}
1185 
1186 	return mb_ies;
1187 }
1188 
1189 
1190 const struct oper_class_map global_op_class[] = {
1191 	{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
1192 	{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
1193 
1194 	/* Do not enable HT40 on 2.4 GHz for P2P use for now */
1195 	{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
1196 	{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
1197 
1198 	{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
1199 	{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
1200 	{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
1201 	{ HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
1202 	{ HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
1203 	{ HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
1204 	{ HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
1205 	{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
1206 	{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
1207 	{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
1208 	{ HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
1209 	{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
1210 	{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
1211 
1212 	/*
1213 	 * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
1214 	 * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
1215 	 * 80 MHz, but currently use the following definition for simplicity
1216 	 * (these center frequencies are not actual channels, which makes
1217 	 * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
1218 	 * care of removing invalid channels.
1219 	 */
1220 	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
1221 	{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
1222 	{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
1223 	{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
1224 	{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
1225 };
1226 
1227 
1228 static enum phy_type ieee80211_phy_type_by_freq(int freq)
1229 {
1230 	enum hostapd_hw_mode hw_mode;
1231 	u8 channel;
1232 
1233 	hw_mode = ieee80211_freq_to_chan(freq, &channel);
1234 
1235 	switch (hw_mode) {
1236 	case HOSTAPD_MODE_IEEE80211A:
1237 		return PHY_TYPE_OFDM;
1238 	case HOSTAPD_MODE_IEEE80211B:
1239 		return PHY_TYPE_HRDSSS;
1240 	case HOSTAPD_MODE_IEEE80211G:
1241 		return PHY_TYPE_ERP;
1242 	case HOSTAPD_MODE_IEEE80211AD:
1243 		return PHY_TYPE_DMG;
1244 	default:
1245 		return PHY_TYPE_UNSPECIFIED;
1246 	};
1247 }
1248 
1249 
1250 /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
1251 enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
1252 {
1253 	if (vht)
1254 		return PHY_TYPE_VHT;
1255 	if (ht)
1256 		return PHY_TYPE_HT;
1257 
1258 	return ieee80211_phy_type_by_freq(freq);
1259 }
1260 
1261 
1262 size_t global_op_class_size = ARRAY_SIZE(global_op_class);
1263 
1264 
1265 /**
1266  * get_ie - Fetch a specified information element from IEs buffer
1267  * @ies: Information elements buffer
1268  * @len: Information elements buffer length
1269  * @eid: Information element identifier (WLAN_EID_*)
1270  * Returns: Pointer to the information element (id field) or %NULL if not found
1271  *
1272  * This function returns the first matching information element in the IEs
1273  * buffer or %NULL in case the element is not found.
1274  */
1275 const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
1276 {
1277 	const u8 *end;
1278 
1279 	if (!ies)
1280 		return NULL;
1281 
1282 	end = ies + len;
1283 
1284 	while (end - ies > 1) {
1285 		if (2 + ies[1] > end - ies)
1286 			break;
1287 
1288 		if (ies[0] == eid)
1289 			return ies;
1290 
1291 		ies += 2 + ies[1];
1292 	}
1293 
1294 	return NULL;
1295 }
1296 
1297 
1298 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
1299 {
1300 	/*
1301 	 * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
1302 	 * OUI (3), OUI type (1).
1303 	 */
1304 	if (len < 6 + attr_len) {
1305 		wpa_printf(MSG_DEBUG,
1306 			   "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
1307 			   len, attr_len);
1308 		return 0;
1309 	}
1310 
1311 	*buf++ = WLAN_EID_VENDOR_SPECIFIC;
1312 	*buf++ = attr_len + 4;
1313 	WPA_PUT_BE24(buf, OUI_WFA);
1314 	buf += 3;
1315 	*buf++ = MBO_OUI_TYPE;
1316 	os_memcpy(buf, attr, attr_len);
1317 
1318 	return 6 + attr_len;
1319 }
1320