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