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 #ifdef AWSS_SUPPORT_APLIST
11 
12 /* storage to store apinfo */
13 struct ap_info *zconfig_aplist = NULL;
14 /* aplist num, less than MAX_APLIST_NUM */
15 uint8_t zconfig_aplist_num = 0;
16 uint8_t zconfig_aplist_id = 0;
17 
awss_init_ieee80211_aplist(void)18 int awss_init_ieee80211_aplist(void)
19 {
20     if (zconfig_aplist) {
21         return 0;
22     }
23     zconfig_aplist =
24         (struct ap_info *)awss_zalloc(sizeof(struct ap_info) * MAX_APLIST_NUM);
25     if (zconfig_aplist == NULL) {
26         return -1;
27     }
28     zconfig_aplist_num = 0;
29     zconfig_aplist_id = 0;
30     return 0;
31 }
32 
awss_deinit_ieee80211_aplist(void)33 int awss_deinit_ieee80211_aplist(void)
34 {
35     if (zconfig_aplist == NULL) {
36         return 0;
37     }
38     HAL_Free(zconfig_aplist);
39     zconfig_aplist = NULL;
40     zconfig_aplist_num = 0;
41     zconfig_aplist_id = 0;
42     return 0;
43 }
44 
zconfig_get_apinfo(uint8_t * mac)45 struct ap_info *zconfig_get_apinfo(uint8_t *mac)
46 {
47     int i;
48 
49     for (i = 0; i < zconfig_aplist_num; i++) {
50         if (!memcmp(zconfig_aplist[i].mac, mac, ETH_ALEN)) {
51             return &zconfig_aplist[i];
52         }
53     }
54 
55     return NULL;
56 }
57 
zconfig_get_apinfo_by_3_byte_mac(uint8_t * last_3_Byte_mac)58 struct ap_info *zconfig_get_apinfo_by_3_byte_mac(uint8_t *last_3_Byte_mac)
59 {
60     int i;
61     uint8_t *local_mac;
62 
63     for (i = 0; i < zconfig_aplist_num; i++) {
64         local_mac = (uint8_t *)(zconfig_aplist[i].mac) + 3;
65         if (!memcmp(local_mac, last_3_Byte_mac, ETH_ALEN - 3)) {
66             return &zconfig_aplist[i];
67         }
68     }
69 
70     return NULL;
71 }
72 
zconfig_get_apinfo_by_ssid(uint8_t * ssid)73 struct ap_info *zconfig_get_apinfo_by_ssid(uint8_t *ssid)
74 {
75     int i;
76 
77     for (i = 0; i < zconfig_aplist_num; i++) {
78         if (!strcmp((char *)zconfig_aplist[i].ssid, (char *)ssid)) {
79             return &zconfig_aplist[i];
80         }
81     }
82 
83     return NULL;
84 }
85 
86 /* 通过ssid前缀 */
zconfig_get_apinfo_by_ssid_prefix(uint8_t * ssid_prefix)87 struct ap_info *zconfig_get_apinfo_by_ssid_prefix(uint8_t *ssid_prefix)
88 {
89     int i;
90     int len = strlen((const char *)ssid_prefix);
91     if (!len) {
92         return NULL;
93     }
94 
95     for (i = 0; i < zconfig_aplist_num; i++) {
96         if (!strncmp((char *)zconfig_aplist[i].ssid, (char *)ssid_prefix,
97                      len)) {
98             /* TODO: first match or best match??? */
99             return &zconfig_aplist[i]; /* first match */
100         }
101     }
102 
103     return NULL;
104 }
105 
str_end_with(const char * str,const char * suffix)106 int str_end_with(const char *str, const char *suffix)
107 {
108     int lenstr, lensuffix;
109     if (!str || !suffix) {
110         return 0;
111     }
112     lenstr = strlen(str);
113     lensuffix = strlen(suffix);
114     if (lensuffix > lenstr) {
115         return 0;
116     }
117     return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
118 }
119 
120 /* 通过ssid后缀 */
zconfig_get_apinfo_by_ssid_suffix(uint8_t * ssid_suffix)121 struct ap_info *zconfig_get_apinfo_by_ssid_suffix(uint8_t *ssid_suffix)
122 {
123     int i;
124     int len = strlen((const char *)ssid_suffix);
125     if (!len) {
126         return NULL;
127     }
128 
129     for (i = 0; i < zconfig_aplist_num; i++) {
130         if (str_end_with((char *)zconfig_aplist[i].ssid, (char *)ssid_suffix)) {
131             /* TODO: first match or best match??? */
132             return &zconfig_aplist[i]; /* first match */
133         }
134     }
135 
136     return NULL;
137 }
138 
139 /**
140  * save apinfo
141  *
142  * @ssid: [IN] ap ssid
143  * @bssid: [IN] ap bssid
144  * @channel: [IN] ap channel
145  * @auth: [IN] optional, ap auth mode, like OPEN/WEP/WPA/WPA2/WPAWPA2
146  * @encry: [IN], ap encryption mode, i.e. NONE/WEP/TKIP/AES/TKIP-AES
147  *
148  * Note:
149  *     1) if ap num exceed zconfig_aplist[], always save at [0]
150  *         but why...I forgot...
151  *     2) always update channel if channel != 0
152  *     3) if chn is locked, save ssid to zc_ssid, because zc_ssid
153  *         can be used for ssid-auto-completion
154  * Return:
155  *     0/success, -1/invalid params(empty ssid/bssid)
156  */
157 
awss_save_apinfo(uint8_t * ssid,uint8_t * bssid,uint8_t channel,uint8_t auth,uint8_t pairwise_cipher,uint8_t group_cipher,signed char rssi)158 int awss_save_apinfo(uint8_t *ssid, uint8_t *bssid, uint8_t channel,
159                      uint8_t auth, uint8_t pairwise_cipher,
160                      uint8_t group_cipher, signed char rssi)
161 {
162     int i;
163 
164     /* ssid, bssid cannot empty, channel can be 0, auth/encry can be invalid */
165     if (!(ssid && bssid)) {
166         return -1;
167     }
168 
169     /* sanity check */
170     if (channel > ZC_MAX_CHANNEL || channel < ZC_MIN_CHANNEL) {
171         channel = 0;
172     } else {
173         zconfig_add_active_channel(channel);
174     }
175 
176     if (auth > ZC_AUTH_TYPE_MAX) {
177         auth = ZC_AUTH_TYPE_INVALID;
178     }
179 
180     if (pairwise_cipher > ZC_ENC_TYPE_MAX) {
181         pairwise_cipher = ZC_ENC_TYPE_INVALID;
182     }
183     if (group_cipher > ZC_ENC_TYPE_MAX) {
184         group_cipher = ZC_ENC_TYPE_INVALID;
185     }
186 
187     /* FIXME: */
188     if (pairwise_cipher == ZC_ENC_TYPE_TKIPAES) {
189         pairwise_cipher = ZC_ENC_TYPE_AES; /* tods */
190     }
191 
192     for (i = 0; i < zconfig_aplist_num; i++) {
193         if (!strncmp(zconfig_aplist[i].ssid, (char *)ssid, ZC_MAX_SSID_LEN) &&
194             !memcmp(zconfig_aplist[i].mac, bssid, ETH_ALEN)) {
195             /* FIXME: useless? */
196             /* found the same bss */
197             if (!zconfig_aplist[i].channel) {
198                 zconfig_aplist[i].channel = channel;
199             }
200             if (zconfig_aplist[i].auth == ZC_AUTH_TYPE_INVALID) {
201                 zconfig_aplist[i].auth = auth;
202             }
203             if (zconfig_aplist[i].encry[0] == ZC_ENC_TYPE_INVALID) {
204                 zconfig_aplist[i].encry[0] = group_cipher;
205             }
206             if (zconfig_aplist[i].encry[1] == ZC_ENC_TYPE_INVALID) {
207                 zconfig_aplist[i].encry[1] = pairwise_cipher;
208             }
209 
210             return 0; /* duplicated ssid */
211         }
212     }
213 
214     i = zconfig_aplist_id % MAX_APLIST_NUM;
215     zconfig_aplist_id++;
216 
217     strncpy((char *)&zconfig_aplist[i].ssid, (const char *)&ssid[0],
218             ZC_MAX_SSID_LEN - 1);
219     memcpy(&zconfig_aplist[i].mac, bssid, ETH_ALEN);
220     zconfig_aplist[i].auth = auth;
221     zconfig_aplist[i].rssi = rssi;
222     zconfig_aplist[i].channel = channel;
223     zconfig_aplist[i].encry[0] = group_cipher;
224     zconfig_aplist[i].encry[1] = pairwise_cipher;
225 
226     awss_trace(
227         "[%d] ssid:%s, mac:%02x%02x%02x%02x%02x%02x, chn:%d, rssi:%d\r\n", i,
228         ssid, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
229         channel, rssi > 0 ? rssi - 256 : rssi);
230     /*
231      * if chn already locked(zc_bssid set),
232      * copy ssid to zc_ssid for ssid-auto-completiont
233      */
234     if (!memcmp(zc_bssid, bssid, ETH_ALEN) && ssid[0] != '\0') {
235         strncpy((char *)zc_ssid, (char const *)ssid, ZC_MAX_SSID_LEN - 1);
236     }
237 
238     zconfig_aplist_num++;
239     zconfig_aplist_num = zconfig_aplist_num >= MAX_APLIST_NUM
240                              ? MAX_APLIST_NUM
241                              : zconfig_aplist_num;
242 
243     return 0;
244 }
245 
246 /*
247  * [IN] ssid or bssid
248  * [OUT] auth, encry, channel
249  */
awss_get_auth_info(uint8_t * ssid,uint8_t * bssid,uint8_t * auth,uint8_t * encry,uint8_t * channel)250 int awss_get_auth_info(uint8_t *ssid, uint8_t *bssid, uint8_t *auth,
251                        uint8_t *encry, uint8_t *channel)
252 {
253     uint8_t *valid_bssid = NULL;
254     struct ap_info *ap_info = NULL;
255 
256     /* sanity check */
257     if (!bssid || !memcmp(bssid, zero_mac, ETH_ALEN)) {
258         valid_bssid = NULL;
259     } else {
260         valid_bssid = bssid;
261     }
262 
263     /* use mac or ssid to search apinfo */
264     if (valid_bssid) {
265         ap_info = zconfig_get_apinfo(valid_bssid);
266     } else {
267         ap_info = zconfig_get_apinfo_by_ssid(ssid);
268     }
269 
270     if (!ap_info) {
271         return 0;
272     }
273 
274     if (auth) {
275         *auth = ap_info->auth;
276     }
277     if (encry) {
278         *encry = ap_info->encry[1]; /* tods side */
279     }
280     if (!valid_bssid && bssid) {
281         memcpy(bssid, ap_info->mac, ETH_ALEN);
282     }
283     if (channel) {
284         *channel = ap_info->channel;
285     }
286 
287     return 1;
288 }
289 
aws_try_adjust_chan(void)290 void aws_try_adjust_chan(void)
291 {
292     struct ap_info *ap = NULL;
293     char ssid[ZC_MAX_SSID_LEN] = { 0 };
294     ap = zconfig_get_apinfo(zc_bssid);
295     if (ap == NULL) {
296         return;
297     }
298     if (zconfig_get_lock_chn() == ap->channel) {
299         return;
300     }
301     if (!zconfig_is_valid_channel(ap->channel)) {
302         return;
303     }
304     strncpy(ssid, (const char *)ap->ssid, ZC_MAX_SSID_LEN - 1);
305 
306 #ifdef AWSS_SUPPORT_AHA
307     if (strlen(ssid) == strlen(zc_default_ssid) &&
308         strncmp(ap->ssid, zc_default_ssid, strlen(zc_default_ssid)) == 0) {
309         return;
310     }
311 #endif
312 
313     aws_set_dst_chan(ap->channel);
314     aws_switch_channel();
315 }
316 
awss_ieee80211_aplist_process(uint8_t * mgmt_header,int len,int link_type,struct parser_res * res,signed char rssi)317 int awss_ieee80211_aplist_process(uint8_t *mgmt_header, int len, int link_type,
318                                   struct parser_res *res, signed char rssi)
319 {
320     uint8_t ssid[ZC_MAX_SSID_LEN] = { 0 }, bssid[ETH_ALEN] = { 0 };
321     uint8_t auth, pairwise_cipher, group_cipher;
322     struct ieee80211_hdr *hdr;
323     int fc, ret, channel;
324 
325     if (mgmt_header == NULL) {
326         return ALINK_INVALID;
327     }
328 
329     hdr = (struct ieee80211_hdr *)mgmt_header;
330     fc = hdr->frame_control;
331 
332     /*
333      * just for save ap in aplist for ssid amend.
334      */
335     if (!ieee80211_is_beacon(fc) && !ieee80211_is_probe_resp(fc)) {
336         return ALINK_INVALID;
337     }
338 
339     ret = ieee80211_get_bssid_2(mgmt_header, bssid);
340     if (ret < 0) {
341         return ALINK_INVALID;
342     }
343 
344     ret = ieee80211_get_ssid(mgmt_header, len, ssid);
345     if (ret < 0) {
346         return ALINK_INVALID;
347     }
348 
349     /*
350      * skip all the aha
351      */
352 #ifdef AWSS_SUPPORT_AHA
353     if (strcmp((const char *)ssid, zc_default_ssid) == 0) {
354         return ALINK_INVALID;
355     }
356 #endif
357 
358     channel = cfg80211_get_bss_channel(mgmt_header, len);
359     rssi = rssi > 0 ? rssi - 256 : rssi;
360 
361     cfg80211_get_cipher_info(mgmt_header, len, &auth, &pairwise_cipher,
362                              &group_cipher);
363     awss_save_apinfo(ssid, bssid, channel, auth, pairwise_cipher, group_cipher,
364                      rssi);
365     return ALINK_INVALID;
366 }
367 
368 #endif
369 
370 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
371 }
372 #endif
373