1 /*
2  * IEEE 802.11 Common routines
3  * Copyright (c) 2002-2019, 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 #include "common/wpa_supplicant_i.h"
16 
17 /**
18  * get_ie - Fetch a specified information element from IEs buffer
19  * @ies: Information elements buffer
20  * @len: Information elements buffer length
21  * @eid: Information element identifier (WLAN_EID_*)
22  * Returns: Pointer to the information element (id field) or %NULL if not found
23  *
24  * This function returns the first matching information element in the IEs
25  * buffer or %NULL in case the element is not found.
26  */
get_ie(const u8 * ies,size_t len,u8 eid)27 const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
28 {
29 	const struct element *elem;
30 
31 	if (!ies)
32 		return NULL;
33 
34 	for_each_element_id(elem, eid, ies, len)
35 		return &elem->id;
36 
37 	return NULL;
38 }
39 
ieee802_11_ie_count(const u8 * ies,size_t ies_len)40 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
41 {
42 	const struct element *elem;
43 	int count = 0;
44 
45 	if (ies == NULL)
46 		return 0;
47 
48 	for_each_element(elem, ies, ies_len)
49 		count++;
50 
51 	return count;
52 }
53 
54 
55 
get_vendor_ie(const u8 * ies,size_t len,u32 vendor_type)56 const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
57 {
58 	const struct element *elem;
59 
60 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
61 		if (elem->datalen >= 4 &&
62 				vendor_type == WPA_GET_BE32(elem->data))
63 			return &elem->id;
64 	}
65 
66 	return NULL;
67 }
68 
69 
mbo_add_ie(u8 * buf,size_t len,const u8 * attr,size_t attr_len)70 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
71 {
72 	/*
73 	 * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
74 	 * OUI (3), OUI type (1).
75 	 */
76 	if (len < 6 + attr_len) {
77 		wpa_printf(MSG_DEBUG,
78 			   "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
79 			   len, attr_len);
80 		return 0;
81 	}
82 
83 	*buf++ = WLAN_EID_VENDOR_SPECIFIC;
84 	*buf++ = attr_len + 4;
85 	WPA_PUT_BE24(buf, OUI_WFA);
86 	buf += 3;
87 	*buf++ = MBO_OUI_TYPE;
88 	os_memcpy(buf, attr, attr_len);
89 
90 	return 6 + attr_len;
91 }
92 
ieee802_11_parse_candidate_list(const char * pos,u8 * nei_rep,size_t nei_rep_len)93 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
94 				    size_t nei_rep_len)
95 {
96 	u8 *nei_pos = nei_rep;
97 	const char *end;
98 
99 	/*
100 	 * BSS Transition Candidate List Entries - Neighbor Report elements
101 	 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
102 	 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
103 	 */
104 	while (pos) {
105 		u8 *nei_start;
106 		long int val;
107 		char *endptr, *tmp;
108 
109 		pos = os_strstr(pos, " neighbor=");
110 		if (!pos)
111 			break;
112 		if (nei_pos + 15 > nei_rep + nei_rep_len) {
113 			wpa_printf(MSG_DEBUG,
114 				   "Not enough room for additional neighbor");
115 			return -1;
116 		}
117 		pos += 10;
118 
119 		nei_start = nei_pos;
120 		*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
121 		nei_pos++; /* length to be filled in */
122 
123 		if (hwaddr_aton2(pos, nei_pos) < 0) {
124 			wpa_printf(MSG_DEBUG, "Invalid BSSID");
125 			return -1;
126 		}
127 		nei_pos += ETH_ALEN;
128 		pos += 17;
129 		if (*pos != ',') {
130 			wpa_printf(MSG_DEBUG, "Missing BSSID Information");
131 			return -1;
132 		}
133 		pos++;
134 
135 		val = strtol(pos, &endptr, 0);
136 		WPA_PUT_LE32(nei_pos, val);
137 		nei_pos += 4;
138 		if (*endptr != ',') {
139 			wpa_printf(MSG_DEBUG, "Missing Operating Class");
140 			return -1;
141 		}
142 		pos = endptr + 1;
143 
144 		*nei_pos++ = atoi(pos); /* Operating Class */
145 		pos = os_strchr(pos, ',');
146 		if (pos == NULL) {
147 			wpa_printf(MSG_DEBUG, "Missing Channel Number");
148 			return -1;
149 		}
150 		pos++;
151 
152 		*nei_pos++ = atoi(pos); /* Channel Number */
153 		pos = os_strchr(pos, ',');
154 		if (pos == NULL) {
155 			wpa_printf(MSG_DEBUG, "Missing PHY Type");
156 			return -1;
157 		}
158 		pos++;
159 
160 		*nei_pos++ = atoi(pos); /* PHY Type */
161 		end = os_strchr(pos, ' ');
162 		tmp = os_strchr(pos, ',');
163 		if (tmp && (!end || tmp < end)) {
164 			/* Optional Subelements (hexdump) */
165 			size_t len;
166 
167 			pos = tmp + 1;
168 			end = os_strchr(pos, ' ');
169 			if (end)
170 				len = end - pos;
171 			else
172 				len = os_strlen(pos);
173 			if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
174 				wpa_printf(MSG_DEBUG,
175 					   "Not enough room for neighbor subelements");
176 				return -1;
177 			}
178 			if (len & 0x01 ||
179 			    hexstr2bin(pos, nei_pos, len / 2) < 0) {
180 				wpa_printf(MSG_DEBUG,
181 					   "Invalid neighbor subelement info");
182 				return -1;
183 			}
184 			nei_pos += len / 2;
185 			pos = end;
186 		}
187 
188 		nei_start[1] = nei_pos - nei_start - 2;
189 	}
190 
191 	return nei_pos - nei_rep;
192 }
193 
194 #ifdef CONFIG_SAE_PK
ieee802_11_parse_vendor_specific(struct wpa_supplicant * wpa_s,const struct element * elem,const u8 * pos)195 static int ieee802_11_parse_vendor_specific(struct wpa_supplicant *wpa_s, const struct element *elem, const u8* pos)
196 {
197 	u32 oui;
198 	oui = WPA_GET_BE24(pos);
199 	switch (oui) {
200 	case OUI_WFA:
201 		switch (pos[3]) {
202 		case SAE_PK_OUI_TYPE:
203 			wpa_s->sae_pk_elems.sae_pk_len = elem->datalen - 4;
204 			wpa_s->sae_pk_elems.sae_pk = (u8*)os_zalloc(sizeof(u8)*(elem->datalen-4));
205 			os_memcpy(wpa_s->sae_pk_elems.sae_pk, pos+4, elem->datalen-4);
206 			break;
207 		default:
208 			wpa_printf(MSG_EXCESSIVE, "Unknown WFA "
209 				"information element ignored "
210 				"(type=%d len=%lu)",
211 				pos[3], (unsigned long) elem->datalen);
212 			return -1;
213 		}
214 		break;
215 	default:
216 		 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
217 			"information element ignored (vendor OUI "
218 			"%02x:%02x:%02x len=%lu)",
219 			pos[0], pos[1], pos[2], (unsigned long) elem->datalen);
220 		return -1;
221 	}
222 
223 	return 0;
224 }
225 
ieee802_11_parse_extension(struct wpa_supplicant * wpa_s,const struct element * elem,const u8 * pos)226 static int ieee802_11_parse_extension(struct wpa_supplicant *wpa_s, const struct element *elem, const u8* pos){
227 	// do not consider extension_id element len in datalen
228 	if (elem->datalen < 1) {
229 		wpa_printf(MSG_DEBUG,
230 			"short information element (Ext)");
231 		return -1;
232 	}
233 	u8 ext_id;
234 	ext_id = *pos++;
235 	switch (ext_id) {
236 	case WLAN_EID_EXT_FILS_KEY_CONFIRM:
237 		wpa_s->sae_pk_elems.fils_key_confirm_len = elem->datalen - 1;
238 		wpa_s->sae_pk_elems.fils_key_confirm = (u8*)os_zalloc(sizeof(u8)*(elem->datalen - 1));
239 		os_memcpy(wpa_s->sae_pk_elems.fils_key_confirm, pos, elem->datalen - 1);
240 		break;
241 	case WLAN_EID_EXT_FILS_PUBLIC_KEY:
242 		wpa_s->sae_pk_elems.fils_pk_len = elem->datalen - 1;
243 		wpa_s->sae_pk_elems.fils_pk = (u8*)os_zalloc(sizeof(u8)*(elem->datalen - 1));
244 		os_memcpy(wpa_s->sae_pk_elems.fils_pk, pos, elem->datalen - 1);
245 		break;
246 	default:
247 		wpa_printf(MSG_EXCESSIVE,
248 			"IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
249 		   ext_id, (unsigned int) elem->datalen-1);
250 		return -1;
251 	}
252 
253 	return 0;
254 }
255 #endif /* CONFIG_SAE_PK */
256 
257 /**
258  * ieee802_11_parse_elems - Parse information elements in management frames
259  * @start: Pointer to the start of IEs
260  * @len: Length of IE buffer in octets
261  * @elems: Data structure for parsed elements
262  * @show_errors: Whether to show parsing errors in debug log
263  * Returns: Parsing result
264  */
ieee802_11_parse_elems(struct wpa_supplicant * wpa_s,const u8 * start,size_t len)265 int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len)
266 {
267 #if defined(CONFIG_RRM) ||  defined(CONFIG_SAE_PK)
268 	const struct element *elem;
269 	u8 unknown = 0;
270 
271 	if (!start)
272 		return 0;
273 
274 	for_each_element(elem, start, len) {
275 		u8 id = elem->id;
276 		const u8 *pos = elem->data;
277 		switch (id) {
278 #ifdef CONFIG_RRM
279 		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
280 			os_memcpy(wpa_s->rrm_ie, pos, 5);
281 			wpa_s->rrm.rrm_used = true;
282 			break;
283 #endif
284 #ifdef CONFIG_SAE_PK
285 		case WLAN_EID_EXTENSION:
286 			if(ieee802_11_parse_extension(wpa_s, elem, pos) != 0){
287 				unknown++;
288 			}
289 			break;
290 		case WLAN_EID_VENDOR_SPECIFIC:
291 			if(ieee802_11_parse_vendor_specific(wpa_s, elem, pos) != 0){
292 				unknown++;
293 			}
294 			break;
295 #endif /*CONFIG_SAE_PK*/
296 #ifdef CONFIG_RRM
297 		case WLAN_EID_EXT_CAPAB:
298 			/* extended caps can go beyond 8 octacts but we aren't using them now */
299 			os_memcpy(wpa_s->extend_caps, pos, 5);
300 			break;
301 #endif
302 		default:
303 			break;
304 
305 		}
306 	}
307 	if (unknown)
308 		return -1;
309 
310 #endif /* defined(CONFIG_RRM) ||  defined(CONFIG_SAE_PK) */
311 	return 0;
312 }
313 
ieee802_11_vendor_ie_concat(const u8 * ies,size_t ies_len,u32 oui_type)314 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
315 					    u32 oui_type)
316 {
317 	struct wpabuf *buf;
318 	const struct element *elem, *found = NULL;
319 
320 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
321 		if (elem->datalen >= 4 &&
322 				WPA_GET_BE32(elem->data) == oui_type) {
323 			found = elem;
324 			break;
325 		}
326 	}
327 
328 	if (!found)
329 		return NULL; /* No specified vendor IE found */
330 
331 	buf = wpabuf_alloc(ies_len);
332 	if (buf == NULL)
333 		return NULL;
334 
335 	/*
336 	 * There may be multiple vendor IEs in the message, so need to
337 	 * concatenate their data fields.
338 	 */
339 	for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
340 		if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
341 			wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
342 	}
343 
344 	return buf;
345 }
346 
ieee802_11_ext_capab(const u8 * ie,unsigned int capab)347 int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
348 {
349 	if (!ie || ie[1] <= capab / 8)
350 		return 0;
351 	return !!(ie[2 + capab / 8] & BIT(capab % 8));
352 }
353 
get_operating_class(u8 chan,int sec_channel)354 u8 get_operating_class(u8 chan, int sec_channel)
355 {
356 	u8 op_class;
357 
358 	if (chan < 1 || chan > 14)
359 		return 0;
360 	if (sec_channel == 1)
361 		op_class = 83;
362 	else if (sec_channel == -1)
363 		op_class = 84;
364 	else
365 		op_class = 81;
366 
367 	return op_class;
368 }
369