ieee802_11_common.c revision 203eadb9eda41a1dde4a583edb4684319e3f399e
1/*
2 * IEEE 802.11 Common routines
3 * Copyright (c) 2002-2013, 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 "ieee802_11_defs.h"
14#include "ieee802_11_common.h"
15
16
17static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
18					    struct ieee802_11_elems *elems,
19					    int show_errors)
20{
21	unsigned int oui;
22
23	/* first 3 bytes in vendor specific information element are the IEEE
24	 * OUI of the vendor. The following byte is used a vendor specific
25	 * sub-type. */
26	if (elen < 4) {
27		if (show_errors) {
28			wpa_printf(MSG_MSGDUMP, "short vendor specific "
29				   "information element ignored (len=%lu)",
30				   (unsigned long) elen);
31		}
32		return -1;
33	}
34
35	oui = WPA_GET_BE24(pos);
36	switch (oui) {
37	case OUI_MICROSOFT:
38		/* Microsoft/Wi-Fi information elements are further typed and
39		 * subtyped */
40		switch (pos[3]) {
41		case 1:
42			/* Microsoft OUI (00:50:F2) with OUI Type 1:
43			 * real WPA information element */
44			elems->wpa_ie = pos;
45			elems->wpa_ie_len = elen;
46			break;
47		case WMM_OUI_TYPE:
48			/* WMM information element */
49			if (elen < 5) {
50				wpa_printf(MSG_MSGDUMP, "short WMM "
51					   "information element ignored "
52					   "(len=%lu)",
53					   (unsigned long) elen);
54				return -1;
55			}
56			switch (pos[4]) {
57			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
58			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
59				/*
60				 * Share same pointer since only one of these
61				 * is used and they start with same data.
62				 * Length field can be used to distinguish the
63				 * IEs.
64				 */
65				elems->wmm = pos;
66				elems->wmm_len = elen;
67				break;
68			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
69				elems->wmm_tspec = pos;
70				elems->wmm_tspec_len = elen;
71				break;
72			default:
73				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
74					   "information element ignored "
75					   "(subtype=%d len=%lu)",
76					   pos[4], (unsigned long) elen);
77				return -1;
78			}
79			break;
80		case 4:
81			/* Wi-Fi Protected Setup (WPS) IE */
82			elems->wps_ie = pos;
83			elems->wps_ie_len = elen;
84			break;
85		default:
86			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
87				   "information element ignored "
88				   "(type=%d len=%lu)",
89				   pos[3], (unsigned long) elen);
90			return -1;
91		}
92		break;
93
94	case OUI_WFA:
95		switch (pos[3]) {
96		case P2P_OUI_TYPE:
97			/* Wi-Fi Alliance - P2P IE */
98			elems->p2p = pos;
99			elems->p2p_len = elen;
100			break;
101		case WFD_OUI_TYPE:
102			/* Wi-Fi Alliance - WFD IE */
103			elems->wfd = pos;
104			elems->wfd_len = elen;
105			break;
106		case HS20_INDICATION_OUI_TYPE:
107			/* Hotspot 2.0 */
108			elems->hs20 = pos;
109			elems->hs20_len = elen;
110			break;
111		case HS20_OSEN_OUI_TYPE:
112			/* Hotspot 2.0 OSEN */
113			elems->osen = pos;
114			elems->osen_len = elen;
115			break;
116		default:
117			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
118				   "information element ignored "
119				   "(type=%d len=%lu)",
120				   pos[3], (unsigned long) elen);
121			return -1;
122		}
123		break;
124
125	case OUI_BROADCOM:
126		switch (pos[3]) {
127		case VENDOR_HT_CAPAB_OUI_TYPE:
128			elems->vendor_ht_cap = pos;
129			elems->vendor_ht_cap_len = elen;
130			break;
131		case VENDOR_VHT_TYPE:
132			if (elen > 4 &&
133			    (pos[4] == VENDOR_VHT_SUBTYPE ||
134			     pos[4] == VENDOR_VHT_SUBTYPE2)) {
135				elems->vendor_vht = pos;
136				elems->vendor_vht_len = elen;
137			} else
138				return -1;
139			break;
140		default:
141			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
142				   "information element ignored "
143				   "(type=%d len=%lu)",
144				   pos[3], (unsigned long) elen);
145			return -1;
146		}
147		break;
148
149	default:
150		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
151			   "information element ignored (vendor OUI "
152			   "%02x:%02x:%02x len=%lu)",
153			   pos[0], pos[1], pos[2], (unsigned long) elen);
154		return -1;
155	}
156
157	return 0;
158}
159
160
161/**
162 * ieee802_11_parse_elems - Parse information elements in management frames
163 * @start: Pointer to the start of IEs
164 * @len: Length of IE buffer in octets
165 * @elems: Data structure for parsed elements
166 * @show_errors: Whether to show parsing errors in debug log
167 * Returns: Parsing result
168 */
169ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
170				struct ieee802_11_elems *elems,
171				int show_errors)
172{
173	size_t left = len;
174	const u8 *pos = start;
175	int unknown = 0;
176
177	os_memset(elems, 0, sizeof(*elems));
178
179	while (left >= 2) {
180		u8 id, elen;
181
182		id = *pos++;
183		elen = *pos++;
184		left -= 2;
185
186		if (elen > left) {
187			if (show_errors) {
188				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
189					   "parse failed (id=%d elen=%d "
190					   "left=%lu)",
191					   id, elen, (unsigned long) left);
192				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
193			}
194			return ParseFailed;
195		}
196
197		switch (id) {
198		case WLAN_EID_SSID:
199			elems->ssid = pos;
200			elems->ssid_len = elen;
201			break;
202		case WLAN_EID_SUPP_RATES:
203			elems->supp_rates = pos;
204			elems->supp_rates_len = elen;
205			break;
206		case WLAN_EID_DS_PARAMS:
207			elems->ds_params = pos;
208			elems->ds_params_len = elen;
209			break;
210		case WLAN_EID_CF_PARAMS:
211		case WLAN_EID_TIM:
212			break;
213		case WLAN_EID_CHALLENGE:
214			elems->challenge = pos;
215			elems->challenge_len = elen;
216			break;
217		case WLAN_EID_ERP_INFO:
218			elems->erp_info = pos;
219			elems->erp_info_len = elen;
220			break;
221		case WLAN_EID_EXT_SUPP_RATES:
222			elems->ext_supp_rates = pos;
223			elems->ext_supp_rates_len = elen;
224			break;
225		case WLAN_EID_VENDOR_SPECIFIC:
226			if (ieee802_11_parse_vendor_specific(pos, elen,
227							     elems,
228							     show_errors))
229				unknown++;
230			break;
231		case WLAN_EID_RSN:
232			elems->rsn_ie = pos;
233			elems->rsn_ie_len = elen;
234			break;
235		case WLAN_EID_PWR_CAPABILITY:
236			break;
237		case WLAN_EID_SUPPORTED_CHANNELS:
238			elems->supp_channels = pos;
239			elems->supp_channels_len = elen;
240			break;
241		case WLAN_EID_MOBILITY_DOMAIN:
242			elems->mdie = pos;
243			elems->mdie_len = elen;
244			break;
245		case WLAN_EID_FAST_BSS_TRANSITION:
246			elems->ftie = pos;
247			elems->ftie_len = elen;
248			break;
249		case WLAN_EID_TIMEOUT_INTERVAL:
250			elems->timeout_int = pos;
251			elems->timeout_int_len = elen;
252			break;
253		case WLAN_EID_HT_CAP:
254			elems->ht_capabilities = pos;
255			elems->ht_capabilities_len = elen;
256			break;
257		case WLAN_EID_HT_OPERATION:
258			elems->ht_operation = pos;
259			elems->ht_operation_len = elen;
260			break;
261		case WLAN_EID_MESH_CONFIG:
262			elems->mesh_config = pos;
263			elems->mesh_config_len = elen;
264			break;
265		case WLAN_EID_MESH_ID:
266			elems->mesh_id = pos;
267			elems->mesh_id_len = elen;
268			break;
269		case WLAN_EID_PEER_MGMT:
270			elems->peer_mgmt = pos;
271			elems->peer_mgmt_len = elen;
272			break;
273		case WLAN_EID_VHT_CAP:
274			elems->vht_capabilities = pos;
275			elems->vht_capabilities_len = elen;
276			break;
277		case WLAN_EID_VHT_OPERATION:
278			elems->vht_operation = pos;
279			elems->vht_operation_len = elen;
280			break;
281		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
282			if (elen != 1)
283				break;
284			elems->vht_opmode_notif = pos;
285			break;
286		case WLAN_EID_LINK_ID:
287			if (elen < 18)
288				break;
289			elems->link_id = pos;
290			break;
291		case WLAN_EID_INTERWORKING:
292			elems->interworking = pos;
293			elems->interworking_len = elen;
294			break;
295		case WLAN_EID_QOS_MAP_SET:
296			if (elen < 16)
297				break;
298			elems->qos_map_set = pos;
299			elems->qos_map_set_len = elen;
300			break;
301		case WLAN_EID_EXT_CAPAB:
302			elems->ext_capab = pos;
303			elems->ext_capab_len = elen;
304			break;
305		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
306			if (elen < 3)
307				break;
308			elems->bss_max_idle_period = pos;
309			break;
310		case WLAN_EID_SSID_LIST:
311			elems->ssid_list = pos;
312			elems->ssid_list_len = elen;
313			break;
314		case WLAN_EID_AMPE:
315			elems->ampe = pos;
316			elems->ampe_len = elen;
317			break;
318		case WLAN_EID_MIC:
319			elems->mic = pos;
320			elems->mic_len = elen;
321			/* after mic everything is encrypted, so stop. */
322			left = elen;
323			break;
324		default:
325			unknown++;
326			if (!show_errors)
327				break;
328			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
329				   "ignored unknown element (id=%d elen=%d)",
330				   id, elen);
331			break;
332		}
333
334		left -= elen;
335		pos += elen;
336	}
337
338	if (left)
339		return ParseFailed;
340
341	return unknown ? ParseUnknown : ParseOK;
342}
343
344
345int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
346{
347	int count = 0;
348	const u8 *pos, *end;
349
350	if (ies == NULL)
351		return 0;
352
353	pos = ies;
354	end = ies + ies_len;
355
356	while (pos + 2 <= end) {
357		if (pos + 2 + pos[1] > end)
358			break;
359		count++;
360		pos += 2 + pos[1];
361	}
362
363	return count;
364}
365
366
367struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
368					    u32 oui_type)
369{
370	struct wpabuf *buf;
371	const u8 *end, *pos, *ie;
372
373	pos = ies;
374	end = ies + ies_len;
375	ie = NULL;
376
377	while (pos + 1 < end) {
378		if (pos + 2 + pos[1] > end)
379			return NULL;
380		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
381		    WPA_GET_BE32(&pos[2]) == oui_type) {
382			ie = pos;
383			break;
384		}
385		pos += 2 + pos[1];
386	}
387
388	if (ie == NULL)
389		return NULL; /* No specified vendor IE found */
390
391	buf = wpabuf_alloc(ies_len);
392	if (buf == NULL)
393		return NULL;
394
395	/*
396	 * There may be multiple vendor IEs in the message, so need to
397	 * concatenate their data fields.
398	 */
399	while (pos + 1 < end) {
400		if (pos + 2 + pos[1] > end)
401			break;
402		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
403		    WPA_GET_BE32(&pos[2]) == oui_type)
404			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
405		pos += 2 + pos[1];
406	}
407
408	return buf;
409}
410
411
412const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
413{
414	u16 fc, type, stype;
415
416	/*
417	 * PS-Poll frames are 16 bytes. All other frames are
418	 * 24 bytes or longer.
419	 */
420	if (len < 16)
421		return NULL;
422
423	fc = le_to_host16(hdr->frame_control);
424	type = WLAN_FC_GET_TYPE(fc);
425	stype = WLAN_FC_GET_STYPE(fc);
426
427	switch (type) {
428	case WLAN_FC_TYPE_DATA:
429		if (len < 24)
430			return NULL;
431		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
432		case WLAN_FC_FROMDS | WLAN_FC_TODS:
433		case WLAN_FC_TODS:
434			return hdr->addr1;
435		case WLAN_FC_FROMDS:
436			return hdr->addr2;
437		default:
438			return NULL;
439		}
440	case WLAN_FC_TYPE_CTRL:
441		if (stype != WLAN_FC_STYPE_PSPOLL)
442			return NULL;
443		return hdr->addr1;
444	case WLAN_FC_TYPE_MGMT:
445		return hdr->addr3;
446	default:
447		return NULL;
448	}
449}
450
451
452int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
453			  const char *name, const char *val)
454{
455	int num, v;
456	const char *pos;
457	struct hostapd_wmm_ac_params *ac;
458
459	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
460	pos = name + 7;
461	if (os_strncmp(pos, "be_", 3) == 0) {
462		num = 0;
463		pos += 3;
464	} else if (os_strncmp(pos, "bk_", 3) == 0) {
465		num = 1;
466		pos += 3;
467	} else if (os_strncmp(pos, "vi_", 3) == 0) {
468		num = 2;
469		pos += 3;
470	} else if (os_strncmp(pos, "vo_", 3) == 0) {
471		num = 3;
472		pos += 3;
473	} else {
474		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
475		return -1;
476	}
477
478	ac = &wmm_ac_params[num];
479
480	if (os_strcmp(pos, "aifs") == 0) {
481		v = atoi(val);
482		if (v < 1 || v > 255) {
483			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
484			return -1;
485		}
486		ac->aifs = v;
487	} else if (os_strcmp(pos, "cwmin") == 0) {
488		v = atoi(val);
489		if (v < 0 || v > 12) {
490			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
491			return -1;
492		}
493		ac->cwmin = v;
494	} else if (os_strcmp(pos, "cwmax") == 0) {
495		v = atoi(val);
496		if (v < 0 || v > 12) {
497			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
498			return -1;
499		}
500		ac->cwmax = v;
501	} else if (os_strcmp(pos, "txop_limit") == 0) {
502		v = atoi(val);
503		if (v < 0 || v > 0xffff) {
504			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
505			return -1;
506		}
507		ac->txop_limit = v;
508	} else if (os_strcmp(pos, "acm") == 0) {
509		v = atoi(val);
510		if (v < 0 || v > 1) {
511			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
512			return -1;
513		}
514		ac->admission_control_mandatory = v;
515	} else {
516		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
517		return -1;
518	}
519
520	return 0;
521}
522
523
524enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
525{
526	enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
527
528	if (freq >= 2412 && freq <= 2472) {
529		mode = HOSTAPD_MODE_IEEE80211G;
530		*channel = (freq - 2407) / 5;
531	} else if (freq == 2484) {
532		mode = HOSTAPD_MODE_IEEE80211B;
533		*channel = 14;
534	} else if (freq >= 4900 && freq < 5000) {
535		mode = HOSTAPD_MODE_IEEE80211A;
536		*channel = (freq - 4000) / 5;
537	} else if (freq >= 5000 && freq < 5900) {
538		mode = HOSTAPD_MODE_IEEE80211A;
539		*channel = (freq - 5000) / 5;
540	} else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
541		mode = HOSTAPD_MODE_IEEE80211AD;
542		*channel = (freq - 56160) / 2160;
543	}
544
545	return mode;
546}
547
548
549static const char *us_op_class_cc[] = {
550	"US", "CA", NULL
551};
552
553static const char *eu_op_class_cc[] = {
554	"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
555	"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
556	"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
557	"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
558};
559
560static const char *jp_op_class_cc[] = {
561	"JP", NULL
562};
563
564static const char *cn_op_class_cc[] = {
565	"CN", "CA", NULL
566};
567
568
569static int country_match(const char *cc[], const char *country)
570{
571	int i;
572
573	if (country == NULL)
574		return 0;
575	for (i = 0; cc[i]; i++) {
576		if (cc[i][0] == country[0] && cc[i][1] == country[1])
577			return 1;
578	}
579
580	return 0;
581}
582
583
584static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
585{
586	switch (op_class) {
587	case 12: /* channels 1..11 */
588	case 32: /* channels 1..7; 40 MHz */
589	case 33: /* channels 5..11; 40 MHz */
590		if (chan < 1 || chan > 11)
591			return -1;
592		return 2407 + 5 * chan;
593	case 1: /* channels 36,40,44,48 */
594	case 2: /* channels 52,56,60,64; dfs */
595	case 22: /* channels 36,44; 40 MHz */
596	case 23: /* channels 52,60; 40 MHz */
597	case 27: /* channels 40,48; 40 MHz */
598	case 28: /* channels 56,64; 40 MHz */
599		if (chan < 36 || chan > 64)
600			return -1;
601		return 5000 + 5 * chan;
602	case 4: /* channels 100-144 */
603	case 24: /* channels 100-140; 40 MHz */
604		if (chan < 100 || chan > 144)
605			return -1;
606		return 5000 + 5 * chan;
607	case 3: /* channels 149,153,157,161 */
608	case 25: /* channels 149,157; 40 MHz */
609	case 26: /* channels 149,157; 40 MHz */
610	case 30: /* channels 153,161; 40 MHz */
611	case 31: /* channels 153,161; 40 MHz */
612		if (chan < 149 || chan > 161)
613			return -1;
614		return 5000 + 5 * chan;
615	case 34: /* 60 GHz band, channels 1..3 */
616		if (chan < 1 || chan > 3)
617			return -1;
618		return 56160 + 2160 * chan;
619	}
620	return -1;
621}
622
623
624static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
625{
626	switch (op_class) {
627	case 4: /* channels 1..13 */
628	case 11: /* channels 1..9; 40 MHz */
629	case 12: /* channels 5..13; 40 MHz */
630		if (chan < 1 || chan > 13)
631			return -1;
632		return 2407 + 5 * chan;
633	case 1: /* channels 36,40,44,48 */
634	case 2: /* channels 52,56,60,64; dfs */
635	case 5: /* channels 36,44; 40 MHz */
636	case 6: /* channels 52,60; 40 MHz */
637	case 8: /* channels 40,48; 40 MHz */
638	case 9: /* channels 56,64; 40 MHz */
639		if (chan < 36 || chan > 64)
640			return -1;
641		return 5000 + 5 * chan;
642	case 3: /* channels 100-140 */
643	case 7: /* channels 100-132; 40 MHz */
644	case 10: /* channels 104-136; 40 MHz */
645	case 16: /* channels 100-140 */
646		if (chan < 100 || chan > 140)
647			return -1;
648		return 5000 + 5 * chan;
649	case 17: /* channels 149,153,157,161,165,169 */
650		if (chan < 149 || chan > 169)
651			return -1;
652		return 5000 + 5 * chan;
653	case 18: /* 60 GHz band, channels 1..4 */
654		if (chan < 1 || chan > 4)
655			return -1;
656		return 56160 + 2160 * chan;
657	}
658	return -1;
659}
660
661
662static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
663{
664	switch (op_class) {
665	case 30: /* channels 1..13 */
666	case 56: /* channels 1..9; 40 MHz */
667	case 57: /* channels 5..13; 40 MHz */
668		if (chan < 1 || chan > 13)
669			return -1;
670		return 2407 + 5 * chan;
671	case 31: /* channel 14 */
672		if (chan != 14)
673			return -1;
674		return 2414 + 5 * chan;
675	case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
676	case 32: /* channels 52,56,60,64 */
677	case 33: /* channels 52,56,60,64 */
678	case 36: /* channels 36,44; 40 MHz */
679	case 37: /* channels 52,60; 40 MHz */
680	case 38: /* channels 52,60; 40 MHz */
681	case 41: /* channels 40,48; 40 MHz */
682	case 42: /* channels 56,64; 40 MHz */
683	case 43: /* channels 56,64; 40 MHz */
684		if (chan < 34 || chan > 64)
685			return -1;
686		return 5000 + 5 * chan;
687	case 34: /* channels 100-140 */
688	case 35: /* channels 100-140 */
689	case 39: /* channels 100-132; 40 MHz */
690	case 40: /* channels 100-132; 40 MHz */
691	case 44: /* channels 104-136; 40 MHz */
692	case 45: /* channels 104-136; 40 MHz */
693	case 58: /* channels 100-140 */
694		if (chan < 100 || chan > 140)
695			return -1;
696		return 5000 + 5 * chan;
697	case 59: /* 60 GHz band, channels 1..4 */
698		if (chan < 1 || chan > 3)
699			return -1;
700		return 56160 + 2160 * chan;
701	}
702	return -1;
703}
704
705
706static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
707{
708	switch (op_class) {
709	case 7: /* channels 1..13 */
710	case 8: /* channels 1..9; 40 MHz */
711	case 9: /* channels 5..13; 40 MHz */
712		if (chan < 1 || chan > 13)
713			return -1;
714		return 2407 + 5 * chan;
715	case 1: /* channels 36,40,44,48 */
716	case 2: /* channels 52,56,60,64; dfs */
717	case 4: /* channels 36,44; 40 MHz */
718	case 5: /* channels 52,60; 40 MHz */
719		if (chan < 36 || chan > 64)
720			return -1;
721		return 5000 + 5 * chan;
722	case 3: /* channels 149,153,157,161,165 */
723	case 6: /* channels 149,157; 40 MHz */
724		if (chan < 149 || chan > 165)
725			return -1;
726		return 5000 + 5 * chan;
727	}
728	return -1;
729}
730
731
732static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
733{
734	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
735	switch (op_class) {
736	case 81:
737		/* channels 1..13 */
738		if (chan < 1 || chan > 13)
739			return -1;
740		return 2407 + 5 * chan;
741	case 82:
742		/* channel 14 */
743		if (chan != 14)
744			return -1;
745		return 2414 + 5 * chan;
746	case 83: /* channels 1..9; 40 MHz */
747	case 84: /* channels 5..13; 40 MHz */
748		if (chan < 1 || chan > 13)
749			return -1;
750		return 2407 + 5 * chan;
751	case 115: /* channels 36,40,44,48; indoor only */
752	case 116: /* channels 36,44; 40 MHz; indoor only */
753	case 117: /* channels 40,48; 40 MHz; indoor only */
754	case 118: /* channels 52,56,60,64; dfs */
755	case 119: /* channels 52,60; 40 MHz; dfs */
756	case 120: /* channels 56,64; 40 MHz; dfs */
757		if (chan < 36 || chan > 64)
758			return -1;
759		return 5000 + 5 * chan;
760	case 121: /* channels 100-140 */
761	case 122: /* channels 100-142; 40 MHz */
762	case 123: /* channels 104-136; 40 MHz */
763		if (chan < 100 || chan > 140)
764			return -1;
765		return 5000 + 5 * chan;
766	case 124: /* channels 149,153,157,161 */
767	case 125: /* channels 149,153,157,161,165,169 */
768	case 126: /* channels 149,157; 40 MHz */
769	case 127: /* channels 153,161; 40 MHz */
770		if (chan < 149 || chan > 161)
771			return -1;
772		return 5000 + 5 * chan;
773	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
774	case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
775		if (chan < 36 || chan > 161)
776			return -1;
777		return 5000 + 5 * chan;
778	case 129: /* center freqs 50, 114; 160 MHz */
779		if (chan < 50 || chan > 114)
780			return -1;
781		return 5000 + 5 * chan;
782	case 180: /* 60 GHz band, channels 1..4 */
783		if (chan < 1 || chan > 4)
784			return -1;
785		return 56160 + 2160 * chan;
786	}
787	return -1;
788}
789
790/**
791 * ieee80211_chan_to_freq - Convert channel info to frequency
792 * @country: Country code, if known; otherwise, global operating class is used
793 * @op_class: Operating class
794 * @chan: Channel number
795 * Returns: Frequency in MHz or -1 if the specified channel is unknown
796 */
797int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
798{
799	int freq;
800
801	if (country_match(us_op_class_cc, country)) {
802		freq = ieee80211_chan_to_freq_us(op_class, chan);
803		if (freq > 0)
804			return freq;
805	}
806
807	if (country_match(eu_op_class_cc, country)) {
808		freq = ieee80211_chan_to_freq_eu(op_class, chan);
809		if (freq > 0)
810			return freq;
811	}
812
813	if (country_match(jp_op_class_cc, country)) {
814		freq = ieee80211_chan_to_freq_jp(op_class, chan);
815		if (freq > 0)
816			return freq;
817	}
818
819	if (country_match(cn_op_class_cc, country)) {
820		freq = ieee80211_chan_to_freq_cn(op_class, chan);
821		if (freq > 0)
822			return freq;
823	}
824
825	return ieee80211_chan_to_freq_global(op_class, chan);
826}
827
828
829int ieee80211_is_dfs(int freq)
830{
831	/* TODO: this could be more accurate to better cover all domains */
832	return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
833}
834
835
836static int is_11b(u8 rate)
837{
838	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
839}
840
841
842int supp_rates_11b_only(struct ieee802_11_elems *elems)
843{
844	int num_11b = 0, num_others = 0;
845	int i;
846
847	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
848		return 0;
849
850	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
851		if (is_11b(elems->supp_rates[i]))
852			num_11b++;
853		else
854			num_others++;
855	}
856
857	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
858	     i++) {
859		if (is_11b(elems->ext_supp_rates[i]))
860			num_11b++;
861		else
862			num_others++;
863	}
864
865	return num_11b > 0 && num_others == 0;
866}
867
868
869const char * fc2str(u16 fc)
870{
871	u16 stype = WLAN_FC_GET_STYPE(fc);
872#define C2S(x) case x: return #x;
873
874	switch (WLAN_FC_GET_TYPE(fc)) {
875	case WLAN_FC_TYPE_MGMT:
876		switch (stype) {
877		C2S(WLAN_FC_STYPE_ASSOC_REQ)
878		C2S(WLAN_FC_STYPE_ASSOC_RESP)
879		C2S(WLAN_FC_STYPE_REASSOC_REQ)
880		C2S(WLAN_FC_STYPE_REASSOC_RESP)
881		C2S(WLAN_FC_STYPE_PROBE_REQ)
882		C2S(WLAN_FC_STYPE_PROBE_RESP)
883		C2S(WLAN_FC_STYPE_BEACON)
884		C2S(WLAN_FC_STYPE_ATIM)
885		C2S(WLAN_FC_STYPE_DISASSOC)
886		C2S(WLAN_FC_STYPE_AUTH)
887		C2S(WLAN_FC_STYPE_DEAUTH)
888		C2S(WLAN_FC_STYPE_ACTION)
889		}
890		break;
891	case WLAN_FC_TYPE_CTRL:
892		switch (stype) {
893		C2S(WLAN_FC_STYPE_PSPOLL)
894		C2S(WLAN_FC_STYPE_RTS)
895		C2S(WLAN_FC_STYPE_CTS)
896		C2S(WLAN_FC_STYPE_ACK)
897		C2S(WLAN_FC_STYPE_CFEND)
898		C2S(WLAN_FC_STYPE_CFENDACK)
899		}
900		break;
901	case WLAN_FC_TYPE_DATA:
902		switch (stype) {
903		C2S(WLAN_FC_STYPE_DATA)
904		C2S(WLAN_FC_STYPE_DATA_CFACK)
905		C2S(WLAN_FC_STYPE_DATA_CFPOLL)
906		C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
907		C2S(WLAN_FC_STYPE_NULLFUNC)
908		C2S(WLAN_FC_STYPE_CFACK)
909		C2S(WLAN_FC_STYPE_CFPOLL)
910		C2S(WLAN_FC_STYPE_CFACKPOLL)
911		C2S(WLAN_FC_STYPE_QOS_DATA)
912		C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
913		C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
914		C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
915		C2S(WLAN_FC_STYPE_QOS_NULL)
916		C2S(WLAN_FC_STYPE_QOS_CFPOLL)
917		C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
918		}
919		break;
920	}
921	return "WLAN_FC_TYPE_UNKNOWN";
922#undef C2S
923}
924