1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4 #include "wifi_provision_internal.h"
5
6 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
7 extern "C" {
8 #endif
9
10 /**
11 * ieee80211_is_ctl - check if type is IEEE80211_FTYPE_CTL
12 * @fc: frame control bytes in little-endian byteorder
13 */
ieee80211_is_ctl(uint16_t fc)14 int ieee80211_is_ctl(uint16_t fc)
15 {
16 return (fc & os_htole16(IEEE80211_FCTL_FTYPE)) ==
17 os_htole16(IEEE80211_FTYPE_CTL);
18 }
19
20 /**
21 * ieee80211_is_data - check if type is IEEE80211_FTYPE_DATA
22 * @fc: frame control bytes in little-endian byteorder
23 */
ieee80211_is_data(uint16_t fc)24 int ieee80211_is_data(uint16_t fc)
25 {
26 return (fc & os_htole16(IEEE80211_FCTL_FTYPE)) ==
27 os_htole16(IEEE80211_FTYPE_DATA);
28 }
29
30 /**
31 * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
32 * @fc: frame control bytes in little-endian byteorder
33 */
ieee80211_has_tods(uint16_t fc)34 int ieee80211_has_tods(uint16_t fc)
35 {
36 return (fc & os_htole16(IEEE80211_FCTL_TODS)) != 0;
37 }
38
39 /**
40 * ieee80211_has_fromds - check if IEEE80211_FCTL_FROMDS is set
41 * @fc: frame control bytes in little-endian byteorder
42 */
ieee80211_has_fromds(uint16_t fc)43 int ieee80211_has_fromds(uint16_t fc)
44 {
45 return (fc & os_htole16(IEEE80211_FCTL_FROMDS)) != 0;
46 }
47
48 /**
49 * ieee80211_has_a4 - check if IEEE80211_FCTL_TODS and IEEE80211_FCTL_FROMDS are
50 * set
51 * @fc: frame control bytes in little-endian byteorder
52 */
ieee80211_has_a4(uint16_t fc)53 int ieee80211_has_a4(uint16_t fc)
54 {
55 uint16_t tmp = os_htole16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
56 return (fc & tmp) == tmp;
57 }
58
59 /**
60 * ieee80211_has_order - check if IEEE80211_FCTL_ORDER is set
61 * @fc: frame control bytes in little-endian byteorder
62 */
ieee80211_has_order(uint16_t fc)63 int ieee80211_has_order(uint16_t fc)
64 {
65 return (fc & os_htole16(IEEE80211_FCTL_ORDER)) != 0;
66 }
67
68 /**
69 * ieee80211_has_protected - check if IEEE80211_FCTL_PROTECTED is set
70 * @fc: frame control bytes in little-endian byteorder
71 */
ieee80211_has_protected(uint16_t fc)72 int ieee80211_has_protected(uint16_t fc)
73 {
74 return (fc & os_htole16(IEEE80211_FCTL_PROTECTED)) != 0;
75 }
76
77 /**
78 * ieee80211_is_data_qos - check if type is IEEE80211_FTYPE_DATA and
79 * IEEE80211_STYPE_QOS_DATA is set
80 * @fc: frame control bytes in little-endian byteorder
81 */
ieee80211_is_data_qos(uint16_t fc)82 int ieee80211_is_data_qos(uint16_t fc)
83 {
84 /*
85 * mask with QOS_DATA rather than IEEE80211_FCTL_STYPE as we just need
86 * to check the one bit
87 */
88 return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_STYPE_QOS_DATA)) ==
89 os_htole16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA);
90 }
91
92 /**
93 * ieee80211_is_data_present - check if type is IEEE80211_FTYPE_DATA and only
94 * data
95 * @fc: frame control bytes in little-endian byteorder
96 */
ieee80211_is_data_exact(uint16_t fc)97 int ieee80211_is_data_exact(uint16_t fc)
98 {
99 uint16_t tmp = fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
100
101 return (tmp == os_htole16(IEEE80211_FTYPE_DATA)) ||
102 (tmp == os_htole16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA));
103 }
104
105 /**
106 * ieee80211_is_beacon - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_BEACON
107 * @fc: frame control bytes in little-endian byteorder
108 */
ieee80211_is_beacon(uint16_t fc)109 int ieee80211_is_beacon(uint16_t fc)
110 {
111 return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
112 os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
113 }
114
115 /**
116 * ieee80211_is_probe_req - check if IEEE80211_FTYPE_MGMT &&
117 * IEEE80211_STYPE_PROBE_REQ
118 * @fc: frame control bytes in little-endian byteorder
119 */
ieee80211_is_probe_req(uint16_t fc)120 int ieee80211_is_probe_req(uint16_t fc)
121 {
122 return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
123 os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ);
124 }
125
126 /**
127 * ieee80211_is_probe_resp - check if IEEE80211_FTYPE_MGMT &&
128 * IEEE80211_STYPE_PROBE_RESP
129 * @fc: frame control bytes in little-endian byteorder
130 */
ieee80211_is_probe_resp(uint16_t fc)131 int ieee80211_is_probe_resp(uint16_t fc)
132 {
133 return (fc & os_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
134 os_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP);
135 }
136
137 /**
138 * ieee80211_get_SA - get pointer to SA
139 * @hdr: the frame
140 *
141 * Given an 802.11 frame, this function returns the offset
142 * to the source address (SA). It does not verify that the
143 * header is long enough to contain the address, and the
144 * header must be long enough to contain the frame control
145 * field.
146 */
ieee80211_get_SA(struct ieee80211_hdr * hdr)147 uint8_t *ieee80211_get_SA(struct ieee80211_hdr *hdr)
148 {
149 if (ieee80211_has_a4(hdr->frame_control))
150 return hdr->addr4;
151 if (ieee80211_has_fromds(hdr->frame_control))
152 return hdr->addr3;
153 return hdr->addr2;
154 }
155
156 /**
157 * ieee80211_get_DA - get pointer to DA
158 * @hdr: the frame
159 *
160 * Given an 802.11 frame, this function returns the offset
161 * to the destination address (DA). It does not verify that
162 * the header is long enough to contain the address, and the
163 * header must be long enough to contain the frame control
164 * field.
165 */
ieee80211_get_DA(struct ieee80211_hdr * hdr)166 uint8_t *ieee80211_get_DA(struct ieee80211_hdr *hdr)
167 {
168 if (ieee80211_has_tods(hdr->frame_control))
169 return hdr->addr3;
170 else
171 return hdr->addr1;
172 }
173
ieee80211_get_BSSID(struct ieee80211_hdr * hdr)174 uint8_t *ieee80211_get_BSSID(struct ieee80211_hdr *hdr)
175 {
176 if (ieee80211_has_tods(hdr->frame_control)) {
177 if (!ieee80211_has_fromds(hdr->frame_control))
178 return hdr->addr1;
179 else
180 return NULL;
181 } else {
182 if (ieee80211_has_fromds(hdr->frame_control))
183 return hdr->addr2;
184 else
185 return hdr->addr3;
186 }
187 }
188
ieee80211_get_bssid_2(uint8_t * in,uint8_t * mac)189 int ieee80211_get_bssid_2(uint8_t *in, uint8_t *mac)
190 {
191 uint8_t *bssid = ieee80211_get_BSSID((struct ieee80211_hdr *)in);
192
193 if (bssid)
194 memcpy(mac, bssid, ETH_ALEN);
195 else
196 return -1;
197
198 return 0;
199 }
200
ieee80211_has_frags(uint16_t fc)201 int ieee80211_has_frags(uint16_t fc)
202 {
203 uint16_t tmp =
204 fc & os_htole16(IEEE80211_FCTL_MOREFRAGS | IEEE80211_FCTL_ORDER);
205
206 return !!tmp;
207 }
208
209 /* DATA: 24B */
210 /* QOS-DATA: 26B */
ieee80211_hdrlen_2(uint16_t fc)211 int ieee80211_hdrlen_2(uint16_t fc)
212 {
213 uint32_t hdrlen = 24;
214
215 if (ieee80211_is_data(fc)) {
216 if (ieee80211_has_a4(fc))
217 hdrlen = 30;
218 if (ieee80211_is_data_qos(fc)) {
219 hdrlen += IEEE80211_QOS_CTL_LEN;
220 if (ieee80211_has_order(fc))
221 hdrlen += IEEE80211_HT_CTL_LEN;
222 }
223 goto out;
224 }
225
226 if (ieee80211_is_ctl(fc)) {
227 /*
228 * ACK and CTS are 10 bytes, all others 16. To see how
229 * to get this condition consider
230 * subtype mask: 0b0000000011110000 (0x00F0)
231 * ACK subtype: 0b0000000011010000 (0x00D0)
232 * CTS subtype: 0b0000000011000000 (0x00C0)
233 * bits that matter: ^^^ (0x00E0)
234 * value of those: 0b0000000011000000 (0x00C0)
235 */
236 if ((fc & os_htole16(0x00E0)) == os_htole16(0x00C0))
237 hdrlen = 10;
238 else
239 hdrlen = 16;
240 }
241
242 out:
243 return hdrlen;
244 }
245
246 /* helpers */
ieee80211_get_radiotap_len(uint8_t * data)247 int ieee80211_get_radiotap_len(uint8_t *data)
248 {
249 struct ieee80211_radiotap_header *hdr =
250 (struct ieee80211_radiotap_header *)data;
251
252 return os_get_unaligned_le16((uint8_t *)&hdr->it_len);
253 }
254
cfg80211_find_ie(uint8_t eid,const uint8_t * ies,int len)255 const uint8_t *cfg80211_find_ie(uint8_t eid, const uint8_t *ies, int len)
256 {
257 while (len > 2 && ies[0] != eid) {
258 len -= ies[1] + 2;
259 ies += ies[1] + 2;
260 }
261 if (len < 2)
262 return NULL;
263 if (len < 2 + ies[1])
264 return NULL;
265 return ies;
266 }
267
268 /**
269 * cfg80211_find_vendor_ie - find vendor specific information element in data
270 *
271 * @oui: vendor OUI
272 * @oui_type: vendor-specific OUI type
273 * @ies: data consisting of IEs
274 * @len: length of data
275 *
276 * Return: %NULL if the vendor specific element ID could not be found or if the
277 * element is invalid (claims to be longer than the given data), or a pointer to
278 * the first byte of the requested element, that is the byte containing the
279 * element ID.
280 *
281 * Note: There are no checks on the element length other than having to fit into
282 * the given data.
283 */
cfg80211_find_vendor_ie(uint32_t oui,uint8_t oui_type,const uint8_t * ies,int len)284 const uint8_t *cfg80211_find_vendor_ie(uint32_t oui, uint8_t oui_type,
285 const uint8_t *ies, int len)
286 {
287 struct ieee80211_vendor_ie *ie;
288 const uint8_t *pos = ies, *end = ies + len;
289 int ie_oui;
290
291 while (pos < end) {
292 pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos, end - pos);
293 if (!pos)
294 return NULL;
295
296 ie = (struct ieee80211_vendor_ie *)pos;
297
298 /* make sure we can access ie->len */
299 /* BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1); */
300
301 if (ie->len < sizeof(*ie))
302 goto cont;
303
304 ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
305 /* awss_trace("oui=%x, type=%x, len=%d\r\n", ie_oui, oui_type, ie->len);
306 */
307 if (ie_oui == oui && ie->oui_type == oui_type)
308 return pos;
309 cont:
310 pos += 2 + ie->len;
311 }
312 return NULL;
313 }
314
315 /**
316 * extract ssid from beacon frame or probe resp frame
317 *
318 * @beacon_frame: [IN] original 80211 beacon frame
319 * @frame_len: [IN] len of beacon frame
320 * @ssid: [OUT] null-terminated string, max len 32 bytes
321 *
322 * Return:
323 * 0/success, -1/failed
324 */
ieee80211_get_ssid(uint8_t * beacon_frame,uint16_t frame_len,uint8_t * ssid)325 int ieee80211_get_ssid(uint8_t *beacon_frame, uint16_t frame_len, uint8_t *ssid)
326 {
327 uint16_t ieoffset =
328 offsetof(struct ieee80211_mgmt,
329 u.beacon.variable); /* same as u.probe_resp.variable */
330 const uint8_t *ptr = cfg80211_find_ie(
331 WLAN_EID_SSID, beacon_frame + ieoffset, frame_len - ieoffset);
332 if (ptr) {
333 uint8_t ssid_len = ptr[1];
334 if (ssid_len <= 32) { /* ssid 32 octets at most */
335 memcpy(ssid, ptr + 2, ssid_len); /* eating EID & len */
336 ssid[ssid_len] = '\0';
337 return 0;
338 }
339 }
340
341 return -1;
342 }
343
344 /**
345 * extract channel from beacon frame or probe resp frame
346 *
347 * @beacon_frame: [IN] original 80211 beacon frame
348 * @frame_len: [IN] len of beacon frame
349 *
350 * Return:
351 * bss channel 1-13, 0--means invalid channel
352 */
cfg80211_get_bss_channel(uint8_t * beacon_frame,uint16_t frame_len)353 int cfg80211_get_bss_channel(uint8_t *beacon_frame, uint16_t frame_len)
354 {
355 uint16_t ieoffset =
356 offsetof(struct ieee80211_mgmt,
357 u.beacon.variable); /* same as u.probe_resp.variable */
358 const uint8_t *ie = beacon_frame + ieoffset;
359 uint16_t ielen = frame_len - ieoffset;
360
361 const uint8_t *tmp;
362 int channel_number = 0;
363
364 tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
365 if (tmp && tmp[1] == 1) {
366 channel_number = tmp[2];
367 } else {
368 tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
369 if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
370 struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
371
372 channel_number = htop->primary_chan;
373 }
374 }
375
376 return channel_number;
377 }
378
379 static const uint8_t WPA_OUI23A_TYPE[] = { 0x00, 0x50, 0xf2, 0x01 };
380 static const uint8_t RSN_SUITE_1X[] = { 0x00, 0x0f, 0xac, 0x01 };
381
382 static const uint8_t WPA_CIPHER_SUITE_NONE23A[] = { 0x00, 0x50, 0xf2, 0x00 };
383 static const uint8_t WPA_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x50, 0xf2, 0x01 };
384 static const uint8_t WPA_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x50, 0xf2, 0x02 };
385 /* static const uint8_t WPA_CIPHER_SUITE_WRAP23A[] = {0x00, 0x50, 0xf2, 0x03};
386 */
387 static const uint8_t WPA_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x50, 0xf2, 0x04 };
388 static const uint8_t WPA_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x50, 0xf2, 0x05 };
389
390 static const uint8_t RSN_CIPHER_SUITE_NONE23A[] = { 0x00, 0x0f, 0xac, 0x00 };
391 static const uint8_t RSN_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x0f, 0xac, 0x01 };
392 static const uint8_t RSN_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x0f, 0xac, 0x02 };
393 /* static const uint8_t RSN_CIPHER_SUITE_WRAP23A[] = {0x00, 0x0f, 0xac, 0x03};
394 */
395 static const uint8_t RSN_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x0f, 0xac, 0x04 };
396 static const uint8_t RSN_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x0f, 0xac, 0x05 };
397
398 #define WPA_SELECTOR_LEN (4)
399 #define RSN_SELECTOR_LEN (4)
400
401 #define BIT(x) (1 << (x))
402 #define WPA_CIPHER_NONE BIT(0)
403 #define WPA_CIPHER_WEP40 BIT(1)
404 #define WPA_CIPHER_WEP104 BIT(2)
405 #define WPA_CIPHER_TKIP BIT(3)
406 #define WPA_CIPHER_CCMP BIT(4)
407
map_cipher_to_encry(uint8_t cipher)408 static uint8_t map_cipher_to_encry(uint8_t cipher)
409 {
410 switch (cipher) {
411 case WPA_CIPHER_CCMP:
412 return ZC_ENC_TYPE_AES;
413 case WPA_CIPHER_TKIP:
414 return ZC_ENC_TYPE_TKIP;
415 case WPA_CIPHER_WEP40:
416 case WPA_CIPHER_WEP104:
417 return ZC_ENC_TYPE_WEP;
418 case WPA_CIPHER_NONE:
419 return ZC_ENC_TYPE_NONE;
420 case (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP):
421 return ZC_ENC_TYPE_TKIPAES;
422 default:
423 awss_warn("unknow cipher type: %x\r\n", cipher);
424 return ZC_ENC_TYPE_INVALID;
425 }
426 }
427
get_wpa_cipher_suite(const uint8_t * s)428 static int get_wpa_cipher_suite(const uint8_t *s)
429 {
430 if (!memcmp(s, WPA_CIPHER_SUITE_NONE23A, WPA_SELECTOR_LEN))
431 return WPA_CIPHER_NONE;
432 if (!memcmp(s, WPA_CIPHER_SUITE_WEP4023A, WPA_SELECTOR_LEN))
433 return WPA_CIPHER_WEP40;
434 if (!memcmp(s, WPA_CIPHER_SUITE_TKIP23A, WPA_SELECTOR_LEN))
435 return WPA_CIPHER_TKIP;
436 if (!memcmp(s, WPA_CIPHER_SUITE_CCMP23A, WPA_SELECTOR_LEN))
437 return WPA_CIPHER_CCMP;
438 if (!memcmp(s, WPA_CIPHER_SUITE_WEP10423A, WPA_SELECTOR_LEN))
439 return WPA_CIPHER_WEP104;
440
441 return 0;
442 }
443
get_wpa2_cipher_suite(const uint8_t * s)444 static int get_wpa2_cipher_suite(const uint8_t *s)
445 {
446 if (!memcmp(s, RSN_CIPHER_SUITE_NONE23A, RSN_SELECTOR_LEN))
447 return WPA_CIPHER_NONE;
448 if (!memcmp(s, RSN_CIPHER_SUITE_WEP4023A, RSN_SELECTOR_LEN))
449 return WPA_CIPHER_WEP40;
450 if (!memcmp(s, RSN_CIPHER_SUITE_TKIP23A, RSN_SELECTOR_LEN))
451 return WPA_CIPHER_TKIP;
452 if (!memcmp(s, RSN_CIPHER_SUITE_CCMP23A, RSN_SELECTOR_LEN))
453 return WPA_CIPHER_CCMP;
454 if (!memcmp(s, RSN_CIPHER_SUITE_WEP10423A, RSN_SELECTOR_LEN))
455 return WPA_CIPHER_WEP104;
456
457 return 0;
458 }
459
cfg80211_parse_wpa_info(const uint8_t * wpa_ie,int wpa_ie_len,uint8_t * group_cipher,uint8_t * pairwise_cipher,uint8_t * is_8021x)460 int cfg80211_parse_wpa_info(const uint8_t *wpa_ie, int wpa_ie_len,
461 uint8_t *group_cipher, uint8_t *pairwise_cipher,
462 uint8_t *is_8021x)
463 {
464 int i, ret = 0;
465 int left, count;
466 const uint8_t *pos;
467
468 if (wpa_ie_len <= 0) {
469 /* No WPA IE - fail silently */
470 return -1;
471 }
472
473 if (wpa_ie[1] != (uint8_t)(wpa_ie_len - 2))
474 return -1;
475
476 pos = wpa_ie;
477
478 pos += 8;
479 left = wpa_ie_len - 8;
480
481 /* group_cipher */
482 if (left >= WPA_SELECTOR_LEN) {
483 *group_cipher = get_wpa_cipher_suite(pos);
484
485 pos += WPA_SELECTOR_LEN;
486 left -= WPA_SELECTOR_LEN;
487 } else if (left > 0) {
488 return -1;
489 }
490
491 /* pairwise_cipher */
492 if (left >= 2) {
493 /* count = le16_to_cpu(*(uint16_t*)pos); */
494 count = os_get_unaligned_le16((uint8_t *)pos);
495 pos += 2;
496 left -= 2;
497
498 if (count == 0 || left < count * WPA_SELECTOR_LEN) {
499 return -1;
500 }
501
502 for (i = 0; i < count; i++) {
503 *pairwise_cipher |= get_wpa_cipher_suite(pos);
504
505 pos += WPA_SELECTOR_LEN;
506 left -= WPA_SELECTOR_LEN;
507 }
508 } else if (left == 1) {
509 return -1;
510 }
511
512 if (is_8021x) {
513 if (left >= 6) {
514 pos += 2;
515 if (!memcmp(pos, WPA_OUI23A_TYPE, 4)) {
516 *is_8021x = 1;
517 }
518 }
519 }
520
521 return ret;
522 }
523
cfg80211_parse_wpa2_info(const uint8_t * rsn_ie,int rsn_ie_len,uint8_t * group_cipher,uint8_t * pairwise_cipher,uint8_t * is_8021x)524 int cfg80211_parse_wpa2_info(const uint8_t *rsn_ie, int rsn_ie_len,
525 uint8_t *group_cipher, uint8_t *pairwise_cipher,
526 uint8_t *is_8021x)
527 {
528 int i, ret = 0;
529 int left, count;
530 const uint8_t *pos;
531
532 if (rsn_ie_len <= 0) {
533 /* No RSN IE - fail silently */
534 return -1;
535 }
536
537 if (*rsn_ie != WLAN_EID_RSN || *(rsn_ie + 1) != (uint8_t)(rsn_ie_len - 2)) {
538 return -1;
539 }
540
541 pos = rsn_ie;
542 pos += 4;
543 left = rsn_ie_len - 4;
544
545 /* group_cipher */
546 if (left >= RSN_SELECTOR_LEN) {
547 *group_cipher = get_wpa2_cipher_suite(pos);
548
549 pos += RSN_SELECTOR_LEN;
550 left -= RSN_SELECTOR_LEN;
551 } else if (left > 0) {
552 return -1;
553 }
554
555 /* pairwise_cipher */
556 if (left >= 2) {
557 /* count = le16_to_cpu(*(uint16_t*)pos); */
558 count = os_get_unaligned_le16((uint8_t *)pos);
559 pos += 2;
560 left -= 2;
561
562 if (count == 0 || left < count * RSN_SELECTOR_LEN) {
563 return -1;
564 }
565
566 for (i = 0; i < count; i++) {
567 *pairwise_cipher |= get_wpa2_cipher_suite(pos);
568
569 pos += RSN_SELECTOR_LEN;
570 left -= RSN_SELECTOR_LEN;
571 }
572 } else if (left == 1) {
573 return -1;
574 }
575
576 if (is_8021x) {
577 if (left >= 6) {
578 pos += 2;
579 if (!memcmp(pos, RSN_SUITE_1X, 4)) {
580 *is_8021x = 1;
581 }
582 }
583 }
584
585 return ret;
586 }
587
588 /**
589 * extract auth/encry type from beacon frame or probe resp frame
590 *
591 * @beacon_frame: [IN] original 80211 beacon frame
592 * @frame_len: [IN] len of beacon frame
593 *
594 * Return:
595 * bss channel 1-13, 0--means invalid channel
596 */
cfg80211_get_cipher_info(uint8_t * beacon_frame,uint16_t frame_len,uint8_t * auth_type,uint8_t * pairwise_cipher_type,uint8_t * group_cipher_type)597 int cfg80211_get_cipher_info(uint8_t *beacon_frame, uint16_t frame_len,
598 uint8_t *auth_type, uint8_t *pairwise_cipher_type,
599 uint8_t *group_cipher_type)
600 {
601 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon_frame;
602 uint8_t is_privacy =
603 !!(mgmt->u.beacon.capab_info & WLAN_CAPABILITY_PRIVACY);
604
605 uint16_t ieoffset =
606 offsetof(struct ieee80211_mgmt,
607 u.beacon.variable); /* same as u.probe_resp.variable */
608 const uint8_t *ie = beacon_frame + ieoffset;
609 uint16_t ielen = frame_len - ieoffset;
610
611 uint8_t auth = 0, group_cipher = 0, pairwise_cipher = 0, is80211X = 0;
612 const uint8_t *tmp;
613 int ret = 0;
614
615 tmp = cfg80211_find_ie(WLAN_EID_RSN, ie, ielen);
616 if (tmp && tmp[1]) {
617 ret = cfg80211_parse_wpa2_info(tmp, tmp[1] + 2, &group_cipher,
618 &pairwise_cipher, &is80211X);
619 if (is80211X)
620 auth = ZC_AUTH_TYPE_WPA28021X;
621 else
622 auth = ZC_AUTH_TYPE_WPA2PSK;
623 group_cipher = map_cipher_to_encry(group_cipher);
624 pairwise_cipher = map_cipher_to_encry(pairwise_cipher);
625 } else {
626 #ifdef AWSS_SUPPORT_SMARTCONFIG_WPS
627 tmp = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
628 WLAN_OUI_TYPE_MICROSOFT_WPA, ie, ielen);
629 if (tmp) {
630 ret = cfg80211_parse_wpa_info(tmp, tmp[1] + 2, &group_cipher,
631 &pairwise_cipher, &is80211X);
632 if (is80211X)
633 auth = ZC_AUTH_TYPE_WPA8021X;
634 else
635 auth = ZC_AUTH_TYPE_WPAPSK;
636 group_cipher = map_cipher_to_encry(group_cipher);
637 pairwise_cipher = map_cipher_to_encry(pairwise_cipher);
638 } else
639 #endif
640 {
641 if (is_privacy) {
642 auth = ZC_AUTH_TYPE_SHARED; /* TODO: WEP */
643 pairwise_cipher = ZC_ENC_TYPE_WEP;
644 group_cipher = ZC_ENC_TYPE_WEP;
645 } else {
646 auth = ZC_AUTH_TYPE_OPEN;
647 pairwise_cipher = ZC_ENC_TYPE_NONE;
648 group_cipher = ZC_ENC_TYPE_NONE;
649 }
650 }
651 }
652
653 if (auth_type)
654 *auth_type = auth;
655 if (pairwise_cipher_type)
656 *pairwise_cipher_type = pairwise_cipher;
657 if (group_cipher_type)
658 *group_cipher_type = group_cipher;
659
660 return ret;
661 }
662
663 /*
664 * make sure 80211 frame is word align, otherwise struct ieee80211_hdr will bug
665 * TODO: code refactor, avoid using memmove
666 */
667 #define check_ieee80211_buf_alignment(buf_addr, len) \
668 do { \
669 if (((unsigned long)(buf_addr) & 0x1) && len > 0) { \
670 uint8_t *word_align_addr = \
671 (uint8_t *)((unsigned long)(buf_addr) & ~0x1); \
672 memmove(word_align_addr, buf_addr, len); \
673 buf_addr = word_align_addr; \
674 } \
675 } while (0)
676
zconfig_remove_link_header(uint8_t ** in,int * len,int link_type)677 uint8_t *zconfig_remove_link_header(uint8_t **in, int *len, int link_type)
678 {
679 int lt_len = 0;
680
681 switch (link_type) {
682 case AWS_LINK_TYPE_NONE:
683 break;
684 case AWS_LINK_TYPE_PRISM:
685 #define PRISM_HDR_LEN 144
686 *in += PRISM_HDR_LEN;
687 *len -= PRISM_HDR_LEN;
688 /* 144, no need to check buf aligment */
689 break;
690 case AWS_LINK_TYPE_80211_RADIO:
691 lt_len = ieee80211_get_radiotap_len(*in);
692 *in += lt_len;
693 *len -= lt_len;
694 check_ieee80211_buf_alignment(*in, *len);
695 break;
696 case AWS_LINK_TYPE_80211_RADIO_AVS:
697 #define WLANCAP_MAGIC_COOKIE_V1 0x80211001
698 #define WLANCAP_MAGIC_COOKIE_V2 0x80211002
699 lt_len = *(uint32_t *)(*in + 4); /* first 4 byte is magic code */
700 *in += lt_len;
701 *len -= lt_len;
702 check_ieee80211_buf_alignment(*in, *len);
703 break;
704 default:
705 awss_debug("un-supported link type!\r\n");
706 break;
707 }
708
709 return *in;
710 }
711
712 struct awss_protocol_couple_type awss_protocol_couple_array[] = {
713 #ifdef AWSS_SUPPORT_HT40
714 { ALINK_HT_CTRL, awss_ieee80211_ht_ctrl_process,
715 awss_recv_callback_ht_ctrl },
716 #endif
717 #ifdef AWSS_SUPPORT_APLIST
718 { ALINK_APLIST, awss_ieee80211_aplist_process, NULL },
719 #endif
720 #ifdef AWSS_SUPPORT_AHA
721 { ALINK_DEFAULT_SSID, awss_ieee80211_aha_process,
722 awss_recv_callback_aha_ssid },
723 #endif
724 #ifndef AWSS_DISABLE_ENROLLEE
725 { ALINK_ZERO_CONFIG, awss_ieee80211_zconfig_process,
726 awss_recv_callback_zconfig },
727 #endif
728 #ifdef AWSS_SUPPORT_SMARTCONFIG_WPS
729 { ALINK_WPS, awss_ieee80211_wps_process, awss_recv_callback_wps },
730 #endif
731 #ifdef AWSS_SUPPORT_SMARTCONFIG
732 { ALINK_BROADCAST, awss_ieee80211_smartconfig_process,
733 awss_recv_callback_smartconfig },
734 #endif
735 #ifdef AWSS_SUPPORT_SMARTCONFIG_MCAST
736 { ALINK_BROADCAST, awss_ieee80211_mcast_smartconfig_process,
737 awss_recv_callback_mcast_smartconfig },
738 #endif
739 #ifdef AWSS_SUPPORT_DISCOVER
740 { ALINK_BROADCAST, aws_discover_callback, NULL },
741 #endif
742 };
743
744 /**
745 * ieee80211_data_extratct - extract 80211 frame info
746 *
747 * @in: [IN] 80211 frame
748 * @len: [IN] 80211 frame len
749 * @link_type: [IN] link type @see enum AWS_LINK_TYPE
750 * @res: [OUT] 80211 frame parser result, see struct parser_res.
751 *
752 * @warning: encry_type may collision with aes & tpip in some cases,
753 * then encry_type will be set to INVALID.
754 * @Return:
755 * @see enum ALINK_TYPE
756 *
757 * @Note: howto deal with radio RSSI signal
758 */
ieee80211_data_extract(uint8_t * in,int len,int link_type,struct parser_res * res,signed char rssi)759 int ieee80211_data_extract(uint8_t *in, int len, int link_type,
760 struct parser_res *res, signed char rssi)
761 {
762 struct ieee80211_hdr *hdr;
763 int alink_type = ALINK_INVALID;
764 int pkt_type = PKG_INVALID;
765 int i, fc;
766
767 hdr = (struct ieee80211_hdr *)zconfig_remove_link_header(&in, &len,
768 link_type);
769 if (len <= 0)
770 goto drop;
771 fc = hdr->frame_control;
772
773 for (i = 0; i < sizeof(awss_protocol_couple_array) /
774 sizeof(awss_protocol_couple_array[0]);
775 i++) {
776 awss_protocol_process_func_type protocol_func =
777 awss_protocol_couple_array[i].awss_protocol_process_func;
778 if (protocol_func == NULL)
779 continue;
780 alink_type = protocol_func((uint8_t *)hdr, len, link_type, res, rssi);
781 if (alink_type != ALINK_INVALID)
782 break;
783 }
784
785 if (alink_type == ALINK_INVALID)
786 goto drop;
787
788 if (alink_type != ALINK_HT_CTRL) {
789 /* convert IEEE 802.11 header + possible LLC headers into Ethernet
790 * header IEEE 802.11 address fields: ToDS FromDS Addr1 Addr2 Addr3
791 * Addr4 0 0 DA SA BSSID n/a 0 1 DA BSSID SA n/a
792 * 1 0 BSSID SA DA n/a
793 * 1 1 RA TA DA SA
794 */
795 res->src = ieee80211_get_SA(hdr);
796 res->dst = ieee80211_get_DA(hdr);
797 res->bssid = ieee80211_get_BSSID(hdr);
798 res->tods = ieee80211_has_tods(fc);
799 }
800
801 do {
802 awss_protocol_finish_func_type finish_func =
803 awss_protocol_couple_array[i].awss_protocol_finish_func;
804 if (finish_func)
805 pkt_type = finish_func(res);
806 } while (0);
807
808 drop:
809 return pkt_type;
810 }
811
812 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
813 }
814 #endif
815