xref: /freebsd/contrib/wpa/src/common/ieee802_11_common.c (revision 3157ba2193f225049c28b3527f499567dae6ad14)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * IEEE 802.11 Common routines
339beb93cSSam Leffler  * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #include "common.h"
1839beb93cSSam Leffler #include "ieee802_11_defs.h"
1939beb93cSSam Leffler #include "ieee802_11_common.h"
2039beb93cSSam Leffler 
2139beb93cSSam Leffler 
2239beb93cSSam Leffler static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen,
2339beb93cSSam Leffler 					    struct ieee802_11_elems *elems,
2439beb93cSSam Leffler 					    int show_errors)
2539beb93cSSam Leffler {
2639beb93cSSam Leffler 	unsigned int oui;
2739beb93cSSam Leffler 
2839beb93cSSam Leffler 	/* first 3 bytes in vendor specific information element are the IEEE
2939beb93cSSam Leffler 	 * OUI of the vendor. The following byte is used a vendor specific
3039beb93cSSam Leffler 	 * sub-type. */
3139beb93cSSam Leffler 	if (elen < 4) {
3239beb93cSSam Leffler 		if (show_errors) {
3339beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "short vendor specific "
3439beb93cSSam Leffler 				   "information element ignored (len=%lu)",
3539beb93cSSam Leffler 				   (unsigned long) elen);
3639beb93cSSam Leffler 		}
3739beb93cSSam Leffler 		return -1;
3839beb93cSSam Leffler 	}
3939beb93cSSam Leffler 
4039beb93cSSam Leffler 	oui = WPA_GET_BE24(pos);
4139beb93cSSam Leffler 	switch (oui) {
4239beb93cSSam Leffler 	case OUI_MICROSOFT:
4339beb93cSSam Leffler 		/* Microsoft/Wi-Fi information elements are further typed and
4439beb93cSSam Leffler 		 * subtyped */
4539beb93cSSam Leffler 		switch (pos[3]) {
4639beb93cSSam Leffler 		case 1:
4739beb93cSSam Leffler 			/* Microsoft OUI (00:50:F2) with OUI Type 1:
4839beb93cSSam Leffler 			 * real WPA information element */
4939beb93cSSam Leffler 			elems->wpa_ie = pos;
5039beb93cSSam Leffler 			elems->wpa_ie_len = elen;
5139beb93cSSam Leffler 			break;
52*3157ba21SRui Paulo 		case WMM_OUI_TYPE:
53*3157ba21SRui Paulo 			/* WMM information element */
5439beb93cSSam Leffler 			if (elen < 5) {
55*3157ba21SRui Paulo 				wpa_printf(MSG_MSGDUMP, "short WMM "
5639beb93cSSam Leffler 					   "information element ignored "
5739beb93cSSam Leffler 					   "(len=%lu)",
5839beb93cSSam Leffler 					   (unsigned long) elen);
5939beb93cSSam Leffler 				return -1;
6039beb93cSSam Leffler 			}
6139beb93cSSam Leffler 			switch (pos[4]) {
62*3157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
63*3157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
64*3157ba21SRui Paulo 				/*
65*3157ba21SRui Paulo 				 * Share same pointer since only one of these
66*3157ba21SRui Paulo 				 * is used and they start with same data.
67*3157ba21SRui Paulo 				 * Length field can be used to distinguish the
68*3157ba21SRui Paulo 				 * IEs.
69*3157ba21SRui Paulo 				 */
70*3157ba21SRui Paulo 				elems->wmm = pos;
71*3157ba21SRui Paulo 				elems->wmm_len = elen;
7239beb93cSSam Leffler 				break;
73*3157ba21SRui Paulo 			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
74*3157ba21SRui Paulo 				elems->wmm_tspec = pos;
75*3157ba21SRui Paulo 				elems->wmm_tspec_len = elen;
7639beb93cSSam Leffler 				break;
7739beb93cSSam Leffler 			default:
78*3157ba21SRui Paulo 				wpa_printf(MSG_MSGDUMP, "unknown WMM "
7939beb93cSSam Leffler 					   "information element ignored "
8039beb93cSSam Leffler 					   "(subtype=%d len=%lu)",
8139beb93cSSam Leffler 					   pos[4], (unsigned long) elen);
8239beb93cSSam Leffler 				return -1;
8339beb93cSSam Leffler 			}
8439beb93cSSam Leffler 			break;
8539beb93cSSam Leffler 		case 4:
8639beb93cSSam Leffler 			/* Wi-Fi Protected Setup (WPS) IE */
8739beb93cSSam Leffler 			elems->wps_ie = pos;
8839beb93cSSam Leffler 			elems->wps_ie_len = elen;
8939beb93cSSam Leffler 			break;
9039beb93cSSam Leffler 		default:
9139beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
9239beb93cSSam Leffler 				   "information element ignored "
9339beb93cSSam Leffler 				   "(type=%d len=%lu)\n",
9439beb93cSSam Leffler 				   pos[3], (unsigned long) elen);
9539beb93cSSam Leffler 			return -1;
9639beb93cSSam Leffler 		}
9739beb93cSSam Leffler 		break;
9839beb93cSSam Leffler 
9939beb93cSSam Leffler 	case OUI_BROADCOM:
10039beb93cSSam Leffler 		switch (pos[3]) {
10139beb93cSSam Leffler 		case VENDOR_HT_CAPAB_OUI_TYPE:
10239beb93cSSam Leffler 			elems->vendor_ht_cap = pos;
10339beb93cSSam Leffler 			elems->vendor_ht_cap_len = elen;
10439beb93cSSam Leffler 			break;
10539beb93cSSam Leffler 		default:
10639beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
10739beb93cSSam Leffler 				   "information element ignored "
10839beb93cSSam Leffler 				   "(type=%d len=%lu)\n",
10939beb93cSSam Leffler 				   pos[3], (unsigned long) elen);
11039beb93cSSam Leffler 			return -1;
11139beb93cSSam Leffler 		}
11239beb93cSSam Leffler 		break;
11339beb93cSSam Leffler 
11439beb93cSSam Leffler 	default:
11539beb93cSSam Leffler 		wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
11639beb93cSSam Leffler 			   "element ignored (vendor OUI %02x:%02x:%02x "
11739beb93cSSam Leffler 			   "len=%lu)",
11839beb93cSSam Leffler 			   pos[0], pos[1], pos[2], (unsigned long) elen);
11939beb93cSSam Leffler 		return -1;
12039beb93cSSam Leffler 	}
12139beb93cSSam Leffler 
12239beb93cSSam Leffler 	return 0;
12339beb93cSSam Leffler }
12439beb93cSSam Leffler 
12539beb93cSSam Leffler 
12639beb93cSSam Leffler /**
12739beb93cSSam Leffler  * ieee802_11_parse_elems - Parse information elements in management frames
12839beb93cSSam Leffler  * @start: Pointer to the start of IEs
12939beb93cSSam Leffler  * @len: Length of IE buffer in octets
13039beb93cSSam Leffler  * @elems: Data structure for parsed elements
13139beb93cSSam Leffler  * @show_errors: Whether to show parsing errors in debug log
13239beb93cSSam Leffler  * Returns: Parsing result
13339beb93cSSam Leffler  */
13439beb93cSSam Leffler ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
13539beb93cSSam Leffler 				struct ieee802_11_elems *elems,
13639beb93cSSam Leffler 				int show_errors)
13739beb93cSSam Leffler {
13839beb93cSSam Leffler 	size_t left = len;
13939beb93cSSam Leffler 	u8 *pos = start;
14039beb93cSSam Leffler 	int unknown = 0;
14139beb93cSSam Leffler 
14239beb93cSSam Leffler 	os_memset(elems, 0, sizeof(*elems));
14339beb93cSSam Leffler 
14439beb93cSSam Leffler 	while (left >= 2) {
14539beb93cSSam Leffler 		u8 id, elen;
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 		id = *pos++;
14839beb93cSSam Leffler 		elen = *pos++;
14939beb93cSSam Leffler 		left -= 2;
15039beb93cSSam Leffler 
15139beb93cSSam Leffler 		if (elen > left) {
15239beb93cSSam Leffler 			if (show_errors) {
15339beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
15439beb93cSSam Leffler 					   "parse failed (id=%d elen=%d "
15539beb93cSSam Leffler 					   "left=%lu)",
15639beb93cSSam Leffler 					   id, elen, (unsigned long) left);
15739beb93cSSam Leffler 				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
15839beb93cSSam Leffler 			}
15939beb93cSSam Leffler 			return ParseFailed;
16039beb93cSSam Leffler 		}
16139beb93cSSam Leffler 
16239beb93cSSam Leffler 		switch (id) {
16339beb93cSSam Leffler 		case WLAN_EID_SSID:
16439beb93cSSam Leffler 			elems->ssid = pos;
16539beb93cSSam Leffler 			elems->ssid_len = elen;
16639beb93cSSam Leffler 			break;
16739beb93cSSam Leffler 		case WLAN_EID_SUPP_RATES:
16839beb93cSSam Leffler 			elems->supp_rates = pos;
16939beb93cSSam Leffler 			elems->supp_rates_len = elen;
17039beb93cSSam Leffler 			break;
17139beb93cSSam Leffler 		case WLAN_EID_FH_PARAMS:
17239beb93cSSam Leffler 			elems->fh_params = pos;
17339beb93cSSam Leffler 			elems->fh_params_len = elen;
17439beb93cSSam Leffler 			break;
17539beb93cSSam Leffler 		case WLAN_EID_DS_PARAMS:
17639beb93cSSam Leffler 			elems->ds_params = pos;
17739beb93cSSam Leffler 			elems->ds_params_len = elen;
17839beb93cSSam Leffler 			break;
17939beb93cSSam Leffler 		case WLAN_EID_CF_PARAMS:
18039beb93cSSam Leffler 			elems->cf_params = pos;
18139beb93cSSam Leffler 			elems->cf_params_len = elen;
18239beb93cSSam Leffler 			break;
18339beb93cSSam Leffler 		case WLAN_EID_TIM:
18439beb93cSSam Leffler 			elems->tim = pos;
18539beb93cSSam Leffler 			elems->tim_len = elen;
18639beb93cSSam Leffler 			break;
18739beb93cSSam Leffler 		case WLAN_EID_IBSS_PARAMS:
18839beb93cSSam Leffler 			elems->ibss_params = pos;
18939beb93cSSam Leffler 			elems->ibss_params_len = elen;
19039beb93cSSam Leffler 			break;
19139beb93cSSam Leffler 		case WLAN_EID_CHALLENGE:
19239beb93cSSam Leffler 			elems->challenge = pos;
19339beb93cSSam Leffler 			elems->challenge_len = elen;
19439beb93cSSam Leffler 			break;
19539beb93cSSam Leffler 		case WLAN_EID_ERP_INFO:
19639beb93cSSam Leffler 			elems->erp_info = pos;
19739beb93cSSam Leffler 			elems->erp_info_len = elen;
19839beb93cSSam Leffler 			break;
19939beb93cSSam Leffler 		case WLAN_EID_EXT_SUPP_RATES:
20039beb93cSSam Leffler 			elems->ext_supp_rates = pos;
20139beb93cSSam Leffler 			elems->ext_supp_rates_len = elen;
20239beb93cSSam Leffler 			break;
20339beb93cSSam Leffler 		case WLAN_EID_VENDOR_SPECIFIC:
20439beb93cSSam Leffler 			if (ieee802_11_parse_vendor_specific(pos, elen,
20539beb93cSSam Leffler 							     elems,
20639beb93cSSam Leffler 							     show_errors))
20739beb93cSSam Leffler 				unknown++;
20839beb93cSSam Leffler 			break;
20939beb93cSSam Leffler 		case WLAN_EID_RSN:
21039beb93cSSam Leffler 			elems->rsn_ie = pos;
21139beb93cSSam Leffler 			elems->rsn_ie_len = elen;
21239beb93cSSam Leffler 			break;
21339beb93cSSam Leffler 		case WLAN_EID_PWR_CAPABILITY:
21439beb93cSSam Leffler 			elems->power_cap = pos;
21539beb93cSSam Leffler 			elems->power_cap_len = elen;
21639beb93cSSam Leffler 			break;
21739beb93cSSam Leffler 		case WLAN_EID_SUPPORTED_CHANNELS:
21839beb93cSSam Leffler 			elems->supp_channels = pos;
21939beb93cSSam Leffler 			elems->supp_channels_len = elen;
22039beb93cSSam Leffler 			break;
22139beb93cSSam Leffler 		case WLAN_EID_MOBILITY_DOMAIN:
22239beb93cSSam Leffler 			elems->mdie = pos;
22339beb93cSSam Leffler 			elems->mdie_len = elen;
22439beb93cSSam Leffler 			break;
22539beb93cSSam Leffler 		case WLAN_EID_FAST_BSS_TRANSITION:
22639beb93cSSam Leffler 			elems->ftie = pos;
22739beb93cSSam Leffler 			elems->ftie_len = elen;
22839beb93cSSam Leffler 			break;
22939beb93cSSam Leffler 		case WLAN_EID_TIMEOUT_INTERVAL:
23039beb93cSSam Leffler 			elems->timeout_int = pos;
23139beb93cSSam Leffler 			elems->timeout_int_len = elen;
23239beb93cSSam Leffler 			break;
23339beb93cSSam Leffler 		case WLAN_EID_HT_CAP:
23439beb93cSSam Leffler 			elems->ht_capabilities = pos;
23539beb93cSSam Leffler 			elems->ht_capabilities_len = elen;
23639beb93cSSam Leffler 			break;
23739beb93cSSam Leffler 		case WLAN_EID_HT_OPERATION:
23839beb93cSSam Leffler 			elems->ht_operation = pos;
23939beb93cSSam Leffler 			elems->ht_operation_len = elen;
24039beb93cSSam Leffler 			break;
24139beb93cSSam Leffler 		default:
24239beb93cSSam Leffler 			unknown++;
24339beb93cSSam Leffler 			if (!show_errors)
24439beb93cSSam Leffler 				break;
24539beb93cSSam Leffler 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
24639beb93cSSam Leffler 				   "ignored unknown element (id=%d elen=%d)",
24739beb93cSSam Leffler 				   id, elen);
24839beb93cSSam Leffler 			break;
24939beb93cSSam Leffler 		}
25039beb93cSSam Leffler 
25139beb93cSSam Leffler 		left -= elen;
25239beb93cSSam Leffler 		pos += elen;
25339beb93cSSam Leffler 	}
25439beb93cSSam Leffler 
25539beb93cSSam Leffler 	if (left)
25639beb93cSSam Leffler 		return ParseFailed;
25739beb93cSSam Leffler 
25839beb93cSSam Leffler 	return unknown ? ParseUnknown : ParseOK;
25939beb93cSSam Leffler }
260