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