1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4 #include "wifi_provision_internal.h"
5 #ifndef AWSS_DISABLE_REGISTRAR
6
7 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
8 extern "C" {
9 #endif
10
11 #define AWSS_JSON_DEV_NAME "deviceName"
12 #define AWSS_JSON_PK "productKey"
13 #define AWSS_JSON_DEV_LIST "data"
14 #define AWSS_JSON_PERIOD "timeout"
15 #define AWSS_JSON_CIPHER "secret"
16 #define AWSS_REPORT_PKT_LEN (512)
17 #define AWSS_REPORT_PARAM_FMT \
18 "{\"awssVer\":%s,\"type\":0,\"ssid\":\"%s\",\"bssid\":\"%s\",\"rssi\":%d," \
19 "\"payload\":[\"%s\"]}"
20
21 static void awss_wifi_mgnt_frame_callback(uint8_t *buffer, int length,
22 signed char rssi, int buffer_type);
23 static void registrar_raw_frame_init(struct enrollee_info *enr);
24 static void registrar_raw_frame_send(void);
25 static void registrar_raw_frame_destroy(void);
26 static void enrollee_report(void);
27 static int enrollee_checkin(void);
28 static int enrollee_enable_somebody_checkin(char *key, char *dev_name,
29 int timeout);
30 static int awss_enrollee_get_dev_info(char *payload, int payload_len,
31 char *product_key, char *dev_name,
32 char *cipher, int *timeout);
33 int registar_yield();
34
35 /* registrar send pkt interval in ms */
36 #define REGISTRAR_TIMEOUT (60)
37 #define REGISTRAR_WORK_TIME (16 * 400)
38
39 static struct enrollee_info enrollee_info[MAX_ENROLLEE_NUM];
40 static char registrar_sched_cnt = 0;
41 static char registrar_inited = 0;
42 static char registrar_id = 0;
43
44 #define ALIBABA_OUI \
45 { \
46 0xD8, 0x96, 0xE0 \
47 }
48
49 #if (REGISTRAR_IDLE_DUTY > 0)
50 uint32_t schedule_timestamp = 0;
51 uint32_t schedule_duration = REGISTRAR_WORK_TIME;
52 uint8_t last_open = 1;
registrar_schedule()53 void registrar_schedule()
54 {
55 uint8_t alibaba_oui[3] = ALIBABA_OUI;
56 unsigned int idle_duty = REGISTRAR_IDLE_DUTY;
57 if ((time_elapsed_ms_since(schedule_timestamp)) < schedule_duration) {
58 return;
59 }
60
61 if (last_open) { /* need to close */
62 HAL_Wifi_Enable_Mgmt_Frame_Filter(
63 FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, (uint8_t *)alibaba_oui,
64 NULL);
65 schedule_duration = REGISTRAR_WORK_TIME * idle_duty;
66 } else {
67 HAL_Wifi_Enable_Mgmt_Frame_Filter(
68 FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK, (uint8_t *)alibaba_oui,
69 awss_wifi_mgnt_frame_callback);
70 schedule_duration = REGISTRAR_WORK_TIME;
71 }
72 schedule_timestamp = os_get_time_ms();
73 last_open = 1 - last_open;
74 }
75 #endif
76
awss_registrar_init(void)77 void awss_registrar_init(void)
78 {
79 uint8_t alibaba_oui[3] = ALIBABA_OUI;
80 if (registrar_inited) {
81 return;
82 }
83
84 memset(enrollee_info, 0, sizeof(enrollee_info));
85 registrar_inited = 1;
86
87 HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK,
88 (uint8_t *)alibaba_oui,
89 awss_wifi_mgnt_frame_callback);
90 #if (REGISTRAR_IDLE_DUTY > 0)
91 schedule_timestamp = os_get_time_ms();
92 schedule_duration = REGISTRAR_WORK_TIME;
93 last_open = 1;
94 #endif
95 }
96
awss_registrar_deinit(void)97 void awss_registrar_deinit(void)
98 {
99 uint8_t alibaba_oui[3] = ALIBABA_OUI;
100 HAL_Wifi_Enable_Mgmt_Frame_Filter(FRAME_BEACON_MASK | FRAME_PROBE_REQ_MASK,
101 (uint8_t *)alibaba_oui, NULL);
102
103 registrar_inited = 0;
104 registrar_sched_cnt = 0;
105 }
106
online_dev_bind_monitor(void * ctx,void * resource,void * remote,void * request)107 int online_dev_bind_monitor(void *ctx, void *resource, void *remote,
108 void *request)
109 {
110 uint8_t i;
111 char *payload = NULL;
112 int payload_len = 0, dev_info_len = 0;
113 char *key = NULL, *dev_name = NULL, *dev_info = NULL;
114
115 payload = awss_cmp_get_coap_payload(request, &payload_len);
116 if (payload == NULL || payload_len == 0) {
117 goto CONNECTAP_MONITOR_END;
118 }
119
120 dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM,
121 &dev_info_len, NULL);
122 if (dev_info == NULL || dev_info_len == 0) {
123 goto CONNECTAP_MONITOR_END;
124 }
125
126 dev_name = awss_zalloc(MAX_DEV_NAME_LEN + 1);
127 key = awss_zalloc(MAX_PK_LEN + 1);
128
129 if (!dev_name || !key) {
130 goto CONNECTAP_MONITOR_END;
131 }
132
133 if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name, NULL,
134 NULL) < 0) {
135 goto CONNECTAP_MONITOR_END;
136 }
137
138 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
139 if (enrollee_info[i].state != ENR_CHECKIN_ONGOING) {
140 continue;
141 }
142
143 if (strlen(dev_name) == enrollee_info[i].dev_name_len &&
144 0 == memcmp(dev_name, enrollee_info[i].dev_name,
145 enrollee_info[i].dev_name_len) &&
146 strlen(key) == enrollee_info[i].pk_len &&
147 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) {
148 enrollee_info[i].state = ENR_FREE;
149 }
150 }
151
152 CONNECTAP_MONITOR_END:
153 if (dev_name) {
154 HAL_Free(dev_name);
155 }
156 if (key) {
157 HAL_Free(key);
158 }
159 return 0;
160 }
161
awss_enrollee_checkin(void * pcontext,void * pclient,void * msg)162 void awss_enrollee_checkin(void *pcontext, void *pclient, void *msg)
163 {
164 #define CHECK_IN_RSP_LEN (64)
165 char *packet = NULL;
166 int len = 0, timeout = 0;
167 int packet_len = CHECK_IN_RSP_LEN, dev_info_len = 0;
168 char *key = NULL, *dev_name = NULL, *dev_info = NULL;
169 uint32_t payload_len;
170 char *payload;
171 int ret;
172 char reply[TOPIC_LEN_MAX] = { 0 };
173
174 ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len);
175
176 if (ret != 0) {
177 goto CHECKIN_FAIL;
178 }
179
180 if (payload == NULL || payload_len == 0) {
181 goto CHECKIN_FAIL;
182 }
183
184 dev_name = awss_zalloc(MAX_DEV_NAME_LEN + 1);
185 packet = awss_zalloc(CHECK_IN_RSP_LEN + 1);
186 key = awss_zalloc(MAX_PK_LEN + 1);
187
188 if (!dev_name || !key || !packet) {
189 goto CHECKIN_FAIL;
190 }
191
192 awss_debug("checkin len:%u, payload:%s\r\n", payload_len, payload);
193
194 dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM,
195 &dev_info_len, NULL);
196 if (dev_info == NULL || dev_info_len == 0) {
197 goto CHECKIN_FAIL;
198 }
199
200 if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name, NULL,
201 &timeout) < 0) {
202 goto CHECKIN_FAIL;
203 }
204
205 enrollee_enable_somebody_checkin(key, dev_name, timeout);
206
207 {
208 char *id = NULL;
209 char id_str[MSG_REQ_ID_LEN] = { 0 };
210 id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len,
211 NULL);
212 memcpy(id_str, id, len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : len);
213 awss_build_packet(AWSS_CMP_PKT_TYPE_RSP, id_str, ILOP_VER,
214 METHOD_EVENT_ZC_CHECKIN, "{}", 200, packet,
215 &packet_len);
216 }
217
218 awss_build_topic(TOPIC_ZC_CHECKIN_REPLY, reply, TOPIC_LEN_MAX);
219 awss_cmp_mqtt_send(reply, packet, packet_len, 1);
220
221 HAL_Free(dev_name);
222 HAL_Free(packet);
223 HAL_Free(key);
224 return;
225
226 CHECKIN_FAIL:
227 if (dev_name) {
228 HAL_Free(dev_name);
229 }
230 if (packet) {
231 HAL_Free(packet);
232 }
233 if (key) {
234 HAL_Free(key);
235 }
236
237 awss_warn("alink checkin failed");
238 return;
239 }
240
enrollee_enable_somebody_cipher(char * key,char * dev_name,char * cipher)241 static int enrollee_enable_somebody_cipher(char *key, char *dev_name,
242 char *cipher)
243 {
244 int i;
245
246 awss_debug("key:%s, dev_name:%s, cipher:%s\r\n", key, dev_name, cipher);
247
248 if (strlen(key) > MAX_PK_LEN || strlen(dev_name) > MAX_DEV_NAME_LEN) {
249 goto out;
250 }
251
252 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
253 awss_debug("enrollee[%d] state %d", i, enrollee_info[i].state);
254 if (enrollee_info[i].state != ENR_CHECKIN_ENABLE) {
255 continue;
256 }
257 if (strlen(dev_name) == enrollee_info[i].dev_name_len &&
258 0 == memcmp(dev_name, enrollee_info[i].dev_name,
259 enrollee_info[i].dev_name_len) &&
260 strlen(key) == enrollee_info[i].pk_len &&
261 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) {
262 uint8_t *key_byte = awss_zalloc(MAX_KEY_LEN + 1);
263 if (NULL == key_byte) {
264 goto out;
265 }
266
267 utils_str_to_hex(cipher, strlen(cipher), key_byte, MAX_KEY_LEN);
268
269 memcpy((char *)&enrollee_info[i].key[0], key_byte, AES_KEY_LEN);
270
271 HAL_Free(key_byte);
272
273 awss_debug("enrollee[%d] state %d->%d", i, enrollee_info[i].state,
274 ENR_CHECKIN_CIPHER);
275 enrollee_info[i].state = ENR_CHECKIN_CIPHER;
276 enrollee_checkin();
277
278 return 1; /* match */
279 }
280 }
281
282 out:
283 return 0; /* mismatch */
284 }
285
enrollee_enable_somebody_checkin(char * key,char * dev_name,int timeout)286 static int enrollee_enable_somebody_checkin(char *key, char *dev_name,
287 int timeout)
288 {
289 int i;
290
291 awss_debug("key:%s, dev_name:%s, timeout:%u\r\n", key, dev_name, timeout);
292 if (strlen(key) > MAX_PK_LEN || strlen(dev_name) > MAX_DEV_NAME_LEN) {
293 goto out;
294 }
295
296 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
297 awss_debug("len:%u---%lu, name:%s---%s\r\n",
298 enrollee_info[i].dev_name_len, strlen(dev_name),
299 enrollee_info[i].dev_name, dev_name);
300 awss_debug("enrollee[%d] state %d", i, enrollee_info[i].state);
301 if (enrollee_info[i].state != ENR_FOUND) {
302 continue;
303 }
304
305 if (strlen(dev_name) == enrollee_info[i].dev_name_len &&
306 0 == memcmp(dev_name, enrollee_info[i].dev_name,
307 enrollee_info[i].dev_name_len) &&
308 strlen(key) == enrollee_info[i].pk_len &&
309 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) {
310 enrollee_info[i].state = ENR_CHECKIN_ENABLE;
311 enrollee_info[i].checkin_priority = 1; /* TODO: not implement yet */
312 enrollee_info[i].checkin_timeout =
313 timeout <= 0 ? REGISTRAR_TIMEOUT : timeout;
314 enrollee_info[i].checkin_timestamp = os_get_time_ms();
315 enrollee_checkin();
316 return 1; /* match */
317 }
318 }
319
320 out:
321 return 0; /* mismatch */
322 }
323
awss_request_cipher_key(int i)324 static int awss_request_cipher_key(int i)
325 {
326 int packet_len = AWSS_REPORT_PKT_LEN - 1;
327 char topic[TOPIC_LEN_MAX] = { 0 };
328 char *param = NULL;
329 char *packet = NULL;
330 if (i < 0) {
331 return -1;
332 }
333 #define AWSS_DEV_CIPHER_FMT \
334 "{\"awssVer\":%s,\"productKey\":\"%s\",\"deviceName\":\"%s\"," \
335 "\"cipherType\":%d, \"random\":\"%s\"}"
336
337 param = awss_zalloc(AWSS_REPORT_PKT_LEN);
338 packet = awss_zalloc(AWSS_REPORT_PKT_LEN);
339 if (param == NULL || packet == NULL) {
340 goto REQ_CIPHER_ERR;
341 }
342
343 {
344 char id[MSG_REQ_ID_LEN] = { 0 };
345 char rand_str[(RANDOM_MAX_LEN << 1) + 1] = { 0 };
346
347 utils_hex_to_str(enrollee_info[i].random, RANDOM_MAX_LEN, rand_str,
348 sizeof(rand_str));
349 HAL_Snprintf(id, MSG_REQ_ID_LEN - 1, "\"%u\"", registrar_id++);
350 HAL_Snprintf(param, AWSS_REPORT_PKT_LEN - 1, AWSS_DEV_CIPHER_FMT,
351 AWSS_VER, enrollee_info[i].pk, enrollee_info[i].dev_name,
352 enrollee_info[i].security, rand_str);
353 awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id, ILOP_VER,
354 METHOD_EVENT_ZC_CIPHER, param, 0, packet,
355 &packet_len);
356 HAL_Free(param);
357 }
358
359 awss_build_topic(TOPIC_ZC_CIPHER, topic, TOPIC_LEN_MAX);
360 awss_cmp_mqtt_send(topic, packet, packet_len, 1);
361
362 HAL_Free(packet);
363
364 return 0;
365
366 REQ_CIPHER_ERR:
367 if (param) {
368 HAL_Free(param);
369 }
370 if (packet) {
371 HAL_Free(packet);
372 }
373
374 return -1;
375 }
376
awss_get_cipher_reply(void * pcontext,void * pclient,void * msg)377 void awss_get_cipher_reply(void *pcontext, void *pclient, void *msg)
378 {
379 int dev_info_len = 0;
380 char *key = NULL, *dev_name = NULL, *dev_info = NULL, *cipher = NULL;
381 uint32_t payload_len;
382 char *payload;
383 int ret;
384
385 ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len);
386
387 if (ret != 0) {
388 goto CIPHER_ERR;
389 }
390
391 if (payload == NULL || payload_len == 0) {
392 goto CIPHER_ERR;
393 }
394
395 dev_name = awss_zalloc(MAX_DEV_NAME_LEN + 1);
396 cipher = awss_zalloc(RANDOM_MAX_LEN * 2 + 1);
397 key = awss_zalloc(MAX_PK_LEN + 1);
398
399 if (!dev_name || !key || !cipher) {
400 goto CIPHER_ERR;
401 }
402
403 awss_debug("cipher len:%u, payload:%s\r\n", payload_len, payload);
404
405 dev_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_LIST,
406 &dev_info_len, NULL);
407 if (dev_info == NULL || dev_info_len == 0) {
408 goto CIPHER_ERR;
409 }
410
411 if (awss_enrollee_get_dev_info(dev_info, dev_info_len, key, dev_name,
412 cipher, NULL) < 0) {
413 goto CIPHER_ERR;
414 }
415
416 enrollee_enable_somebody_cipher(key, dev_name, cipher);
417
418 HAL_Free(dev_name);
419 HAL_Free(cipher);
420 HAL_Free(key);
421
422 return;
423 CIPHER_ERR:
424 if (dev_name) {
425 HAL_Free(dev_name);
426 }
427 if (cipher) {
428 HAL_Free(cipher);
429 }
430 if (key) {
431 HAL_Free(key);
432 }
433 return;
434 }
435
436 /* 1 -- checkin onging, 0 -- idle */
enrollee_checkin(void)437 static int enrollee_checkin(void)
438 {
439 int pri = 65536;
440 uint8_t i, check = 0;
441 uint8_t checkin_new = 0xff, get_cipher = 0xff;
442
443 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
444 switch (enrollee_info[i].state) {
445 case ENR_CHECKIN_ENABLE:
446 if (pri > enrollee_info[i].checkin_priority) {
447 pri = enrollee_info[i].checkin_priority;
448 checkin_new = i;
449 check = 1;
450 }
451 break;
452 case ENR_CHECKIN_CIPHER:
453 get_cipher = i;
454 check = 1;
455 break;
456 case ENR_CHECKIN_ONGOING:
457 goto ongoing;
458 default:
459 break;
460 }
461 }
462
463 /* no device need to setup */
464 if (check == 0) {
465 return 0;
466 }
467
468 awss_debug("cn:%d, ci:%d, c:%d\r\n", checkin_new, get_cipher, check);
469
470 if (get_cipher != 0xff) {
471 goto checkin_ongoing;
472 }
473
474 /* request cipher */
475 awss_request_cipher_key(checkin_new);
476 return 1;
477
478 /* checkin_new: */
479 checkin_ongoing:
480 awss_debug("enrollee[%d] state %d->%d", get_cipher,
481 enrollee_info[get_cipher].state, ENR_CHECKIN_ONGOING);
482 enrollee_info[get_cipher].state = ENR_CHECKIN_ONGOING;
483 enrollee_info[get_cipher].checkin_timestamp = os_get_time_ms();
484 registrar_raw_frame_init(&enrollee_info[get_cipher]);
485 i = get_cipher;
486
487 /* undergoing */
488 ongoing:
489 registrar_raw_frame_send();
490 awss_debug("registrar_raw_frame_send");
491 if (time_elapsed_ms_since(enrollee_info[i].checkin_timestamp) >
492 enrollee_info[i].checkin_timeout * 1000) {
493 memset(&enrollee_info[i], 0, sizeof(enrollee_info[0]));
494 awss_debug("enrollee[%d] state %d->%d", i, enrollee_info[i].state,
495 ENR_CHECKIN_END);
496 enrollee_info[i].state =
497 ENR_CHECKIN_END; /* FIXME: remove this state? */
498 awss_debug("enrollee[%d] state %d->%d", i, enrollee_info[i].state,
499 ENR_FREE);
500 enrollee_info[i].state = ENR_FREE;
501 registrar_raw_frame_destroy();
502 }
503
504 return 1;
505 }
506
awss_report_set_interval(char * key,char * dev_name,int interval)507 int awss_report_set_interval(char *key, char *dev_name, int interval)
508 {
509 int i;
510
511 awss_debug("key:%s, dev_name:%s, interval:%u\r\n", key, dev_name, interval);
512 if (strlen(key) > MAX_PK_LEN || strlen(dev_name) > MAX_DEV_NAME_LEN) {
513 return -1;
514 }
515
516 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
517 if (enrollee_info[i].state != ENR_FOUND) {
518 continue;
519 }
520
521 if (strlen(dev_name) == enrollee_info[i].dev_name_len &&
522 0 == memcmp(dev_name, enrollee_info[i].dev_name,
523 enrollee_info[i].dev_name_len) &&
524 strlen(key) == enrollee_info[i].pk_len &&
525 0 == memcmp(key, enrollee_info[i].pk, enrollee_info[i].pk_len)) {
526 enrollee_info[i].interval =
527 interval <= 0 ? REGISTRAR_TIMEOUT : interval;
528 enrollee_checkin();
529 return 0; /* match */
530 }
531 }
532
533 return -1;
534 }
535
awss_enrollee_get_dev_info(char * payload,int payload_len,char * product_key,char * dev_name,char * cipher,int * timeout)536 static int awss_enrollee_get_dev_info(char *payload, int payload_len,
537 char *product_key, char *dev_name,
538 char *cipher, int *timeout)
539 {
540 char *elem = NULL;
541 int len = 0;
542 if (product_key == NULL || dev_name == NULL) {
543 return -1;
544 }
545
546 elem =
547 json_get_value_by_name(payload, payload_len, AWSS_JSON_PK, &len, NULL);
548 if (len > MAX_PK_LEN || elem == NULL) {
549 return -1;
550 }
551
552 memcpy(product_key, elem, len);
553
554 len = 0;
555 elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_NAME,
556 &len, NULL);
557 if (len > MAX_DEV_NAME_LEN || elem == NULL) {
558 return -1;
559 }
560
561 memcpy(dev_name, elem, len);
562
563 len = 0;
564 elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_PERIOD, &len,
565 NULL);
566 if (elem && timeout) {
567 *timeout = atoi(elem);
568 }
569
570 len = 0;
571 elem = json_get_value_by_name(payload, payload_len, AWSS_JSON_CIPHER, &len,
572 NULL);
573 if (elem && cipher && len <= RANDOM_MAX_LEN * 2) {
574 memcpy(cipher, elem, len);
575 }
576
577 return 0;
578 }
579
awss_report_enrollee_reply(void * pcontext,void * pclient,void * msg)580 void awss_report_enrollee_reply(void *pcontext, void *pclient, void *msg)
581 {
582 int interval = 0;
583 int dev_list_len = 0;
584 char *dev_list = NULL;
585 char *key = NULL, *dev_name = NULL;
586 uint32_t payload_len;
587 char *payload;
588 int ret;
589 char *str_pos, *entry;
590 int entry_len, type;
591
592 ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len);
593
594 if (ret != 0) {
595 goto REPORT_REPLY_FAIL;
596 }
597
598 if (payload == NULL || payload_len == 0) {
599 goto REPORT_REPLY_FAIL;
600 }
601
602 awss_debug("found reply:%s\r\n", payload);
603 dev_name = awss_zalloc(MAX_DEV_NAME_LEN + 1);
604 key = awss_zalloc(MAX_PK_LEN + 1);
605
606 if (!dev_name || !key) {
607 goto REPORT_REPLY_FAIL;
608 }
609
610 dev_list = json_get_value_by_name(payload, payload_len, AWSS_JSON_DEV_LIST,
611 &dev_list_len, NULL);
612 if (dev_list == NULL) {
613 goto REPORT_REPLY_FAIL;
614 }
615
616 json_array_for_each_entry(dev_list, dev_list_len, str_pos, entry, entry_len,
617 type)
618 {
619 memset(dev_name, 0, MAX_DEV_NAME_LEN + 1);
620 memset(key, 0, MAX_PK_LEN + 1);
621 if (awss_enrollee_get_dev_info(entry, entry_len, key, dev_name, NULL,
622 &interval) < 0) {
623 continue;
624 }
625
626 awss_report_set_interval(key, dev_name, interval);
627 }
628
629 HAL_Free(dev_name);
630 HAL_Free(key);
631 return;
632
633 REPORT_REPLY_FAIL:
634 if (dev_name) {
635 HAL_Free(dev_name);
636 }
637 if (key) {
638 HAL_Free(key);
639 }
640
641 awss_warn("ilop report enrollee failed");
642 return;
643 }
644
awss_report_enrollee(uint8_t * payload,int payload_len,signed char rssi)645 int awss_report_enrollee(uint8_t *payload, int payload_len, signed char rssi)
646 {
647 int i;
648 char *payload_str = NULL;
649 char *param = NULL, *packet = NULL;
650 int packet_len = AWSS_REPORT_PKT_LEN - 1;
651 char topic[TOPIC_LEN_MAX] = { 0 };
652
653 payload_str = awss_zalloc(payload_len * 2 + 1);
654 param = awss_zalloc(AWSS_REPORT_PKT_LEN);
655 packet = awss_zalloc(AWSS_REPORT_PKT_LEN);
656 if (!payload_str || !param || !packet) {
657 goto REPORT_FAIL;
658 }
659
660 {
661 char id[MSG_REQ_ID_LEN] = { 0 };
662 uint8_t bssid[OS_ETH_ALEN] = { 0 };
663 char ssid[OS_MAX_SSID_LEN + 1] = { 0 };
664 char bssid_str[OS_ETH_ALEN * 2 + 6] = { 0 };
665
666 HAL_Wifi_Get_Ap_Info(ssid, NULL, bssid);
667 sprintf(bssid_str, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[0], bssid[1],
668 bssid[2], bssid[3], bssid[4], bssid[5]);
669
670 for (i = 0; i < payload_len; i++) {
671 sprintf(&payload_str[i * 2], "%02X", payload[i]);
672 }
673
674 payload_str[payload_len * 2] =
675 '\0'; /* sprintf not add '\0' in the end of string in qcom */
676
677 HAL_Snprintf(id, MSG_REQ_ID_LEN - 1, "\"%u\"", registrar_id++);
678
679 HAL_Snprintf(param, AWSS_REPORT_PKT_LEN - 1, AWSS_REPORT_PARAM_FMT,
680 AWSS_VER, ssid, bssid_str, rssi > 0 ? rssi - 256 : rssi,
681 payload_str);
682 HAL_Free(payload_str);
683 awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id, ILOP_VER,
684 METHOD_EVENT_ZC_ENROLLEE, param, 0, packet,
685 &packet_len);
686 HAL_Free(param);
687 }
688
689 awss_build_topic(TOPIC_ZC_ENROLLEE, topic, TOPIC_LEN_MAX);
690 awss_debug("topic:%s, packet:%s, method:%s\r\n", topic, packet,
691 METHOD_EVENT_ZC_ENROLLEE);
692
693 awss_cmp_mqtt_send(topic, packet, packet_len, 1);
694
695 HAL_Free(packet);
696 return 0;
697
698 REPORT_FAIL:
699 if (payload_str) {
700 HAL_Free(payload_str);
701 }
702 if (packet) {
703 HAL_Free(packet);
704 }
705 if (param) {
706 HAL_Free(param);
707 }
708
709 return -1;
710 }
711
712 /* consumer */
enrollee_report(void)713 static void enrollee_report(void)
714 {
715 int i;
716 #if defined(AWSS_SUPPORT_AHA)
717 char ssid[OS_MAX_SSID_LEN + 1] = { 0 };
718 HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL);
719 if (!strcmp(ssid, DEFAULT_SSID)) {
720 return; /* ignore enrollee in 'aha' mode */
721 }
722 #endif
723
724 /* evict timeout enrollee */
725 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
726 struct enrollee_info *enrollee = &enrollee_info[i];
727 switch (enrollee->state) {
728 case ENR_FOUND:
729 {
730 if (time_elapsed_ms_since(enrollee->report_timestamp) >
731 enrollee->interval * 1000) {
732 memset(enrollee, 0, sizeof(enrollee_info[0]));
733 enrollee->state = ENR_FREE;
734 }
735 break;
736 }
737 case ENR_IN_QUEUE:
738 {
739 uint16_t idx = 0;
740 int ret = -1;
741 uint16_t payload_len =
742 1 + enrollee->dev_name_len + 1 + enrollee->pk_len + 1 +
743 enrollee->rand_len + 3 + enrollee->sign_len;
744 uint8_t *payload = HAL_Malloc(payload_len + 1);
745 if (payload == NULL) {
746 break;
747 }
748
749 payload[idx++] = enrollee->dev_name_len;
750 memcpy(&payload[idx], enrollee->dev_name,
751 enrollee->dev_name_len);
752 idx += enrollee->dev_name_len;
753
754 payload[idx++] = enrollee->pk_len;
755 memcpy(&payload[idx], enrollee->pk, enrollee->pk_len);
756 idx += enrollee->pk_len;
757
758 payload[idx++] = enrollee->rand_len;
759 memcpy(&payload[idx], &enrollee->random, enrollee->rand_len);
760 idx += enrollee->rand_len;
761
762 payload[idx++] = enrollee->security;
763 payload[idx++] = enrollee->sign_method;
764 payload[idx++] = enrollee->sign_len;
765 memcpy(&payload[idx], &enrollee->sign, enrollee->sign_len);
766 idx += enrollee->sign_len;
767
768 ret = awss_report_enrollee(payload, idx, enrollee->rssi);
769
770 enrollee->state = ENR_FOUND;
771 enrollee->report_timestamp = os_get_time_ms();
772
773 awss_trace("enrollee report result:%s, period:%dms\n",
774 ret == 0 ? "success" : "failed",
775 enrollee->interval * 1000);
776
777 HAL_Free(payload);
778 break;
779 }
780 default:
781 break;
782 }
783 }
784 }
785
786 int enrollee_put(struct enrollee_info *in);
787
process_enrollee_ie(const uint8_t * ie,signed char rssi)788 int process_enrollee_ie(const uint8_t *ie, signed char rssi)
789 {
790 struct enrollee_info tmp_enrollee = { 0 };
791 /* suppose enrollee_ie is complete */
792 #define ENROLLEE_IE_HDR (6)
793 /* copy to tmp_enrollee */
794 ie += ENROLLEE_IE_HDR;
795
796 if (ie[0] != DEVICE_TYPE_VERSION) {
797 awss_warn("enrollee(devtype/ver=%d not supported!", ie[0]);
798 return -1;
799 }
800 tmp_enrollee.dev_type_ver = ie[0];
801 ie++; /* eating dev_type_ver */
802
803 if (ie[0] > MAX_DEV_NAME_LEN) {
804 awss_warn("enrollee(dev_name_len=%d out of range!\r\n", ie[0]);
805 return -1;
806 }
807 tmp_enrollee.dev_name_len = ie[0];
808 memcpy(tmp_enrollee.dev_name, &ie[1], ie[0]);
809 ie += ie[0] + 1; /* eating dev_name[n], dev_name_len */
810
811 if (ie[0] != ENROLLEE_FRAME_TYPE) {
812 awss_warn("enrollee(frametype=%d invalid!\r\n", ie[0]);
813 return -1;
814 }
815 tmp_enrollee.frame_type = ie[0];
816 ie++; /* eating frame type */
817
818 if (ie[0] > MAX_PK_LEN) {
819 awss_warn("enrollee(pk_len=%d invalid!\r\n", ie[0]);
820 return -1;
821 }
822 tmp_enrollee.pk_len = ie[0];
823 memcpy(tmp_enrollee.pk, &ie[1], ie[0]);
824 ie += ie[0] + 1; /* eating pk[n], pk_len */
825
826 if (ie[0] != RANDOM_MAX_LEN) {
827 awss_warn("enrollee(rand_len=%d invalid!\r\n", ie[0]);
828 return -1;
829 }
830 tmp_enrollee.rand_len = ie[0];
831 memcpy(tmp_enrollee.random, &ie[1], RANDOM_MAX_LEN);
832 ie += ie[0] + 1; /* eating random[n], rand_len */
833
834 if (ie[0] > 5 || ie[0] < 3) {
835 awss_warn("enrollee(security=%d invalid!\r\n", ie[0]);
836 return -1;
837 }
838 if (ie[1] > 1) {
839 awss_warn("enrollee(sign_method=%d invalid!\r\n", ie[1]);
840 return -1;
841 }
842 if (ie[2] != ENROLLEE_SIGN_SIZE) {
843 awss_warn("enrollee(sign_len=%d invalid!\r\n", ie[2]);
844 return -1;
845 }
846 tmp_enrollee.security = ie[0];
847 tmp_enrollee.sign_method = ie[1];
848 tmp_enrollee.sign_len = ie[2];
849
850 memcpy(tmp_enrollee.sign, &ie[3], ie[2]);
851 ie += ie[2] + 3; /* eating signature[n], security, sign_method, sign_len */
852
853 tmp_enrollee.rssi = rssi;
854
855 enrollee_put(&tmp_enrollee);
856
857 return 0;
858 }
859
860 /* producer */
861 /*
862 * 1: already saved, update timestamp
863 * 0: new saved
864 * -1: no slot to save, drop
865 */
enrollee_put(struct enrollee_info * in)866 int enrollee_put(struct enrollee_info *in)
867 {
868 uint8_t i, empty_slot = MAX_ENROLLEE_NUM;
869 do {
870 #if defined(AWSS_SUPPORT_AHA)
871 char ssid[OS_MAX_SSID_LEN + 1] = { 0 };
872 #endif
873 /* reduce stack used */
874 if (in == NULL ||
875 !HAL_Sys_Net_Is_Ready()) { /* not ready to work as registerar */
876 return -1;
877 }
878 #if defined(AWSS_SUPPORT_AHA)
879 HAL_Wifi_Get_Ap_Info(ssid, NULL, NULL);
880 if (!strcmp(ssid, DEFAULT_SSID)) {
881 return -1; /* ignore enrollee in 'aha' mode */
882 }
883 #endif
884 } while (0);
885
886 for (i = 0; i < MAX_ENROLLEE_NUM; i++) {
887 if (enrollee_info[i].state) {
888 if (in->dev_name_len == enrollee_info[i].dev_name_len &&
889 0 == memcmp(in->dev_name, enrollee_info[i].dev_name,
890 enrollee_info[i].dev_name_len) &&
891 in->pk_len == enrollee_info[i].pk_len &&
892 0 == memcmp(in->pk, enrollee_info[i].pk,
893 enrollee_info[i].pk_len)) {
894 if (enrollee_info[i].state == ENR_FOUND &&
895 time_elapsed_ms_since(enrollee_info[i].report_timestamp) >
896 enrollee_info[i].interval * 1000) {
897 enrollee_report();
898 }
899 if (enrollee_info[i].state !=
900 ENR_IN_QUEUE) { /* already reported */
901 if ((0 != memcmp(&(enrollee_info[i].random[0]),
902 &(in->random[0]), RANDOM_MAX_LEN)) &&
903 (ENR_CHECKIN_ONGOING == enrollee_info[i].state)) {
904 enrollee_info[i].state = ENR_CHECKIN_ENABLE;
905 memset(&(enrollee_info[i].random[0]), 0,
906 RANDOM_MAX_LEN);
907 memcpy(&(enrollee_info[i].random[0]), &(in->random[0]),
908 RANDOM_MAX_LEN);
909 memset(&(enrollee_info[i].sign), 0,
910 enrollee_info[i].sign_len);
911 enrollee_info[i].sign_len = in->sign_len;
912 memcpy(&(enrollee_info[i].sign), &(in->sign),
913 in->sign_len);
914 awss_trace("fix diff random, %s, %s", in->dev_name,
915 enrollee_info[i].dev_name);
916 } /* Fix device name not match issue.
917 It happens only when the enrollee reboots during
918 wifi-provision provison process, thus the random and sign
919 changes. The registar is not aware of that, keeping on
920 broadcasting wifi-provision info encrypted with previous
921 random and sign. To fix this issue, the registar has to
922 regenerate wifi-provision info when it detectes enrollee's
923 random changes. */
924
925 return 1;
926 }
927 memcpy(&enrollee_info[i], in, ENROLLEE_INFO_HDR_SIZE);
928 enrollee_info[i].rssi =
929 (2 * enrollee_info[i].rssi + in->rssi) / 3;
930 return 1; /* wait for report */
931 }
932 } else if (enrollee_info[i].state == ENR_FREE &&
933 empty_slot >= MAX_ENROLLEE_NUM) {
934 empty_slot = i;
935 }
936 }
937
938 if (empty_slot >= MAX_ENROLLEE_NUM) {
939 return -1; /* no slot to save */
940 }
941
942 /* new enrollee */
943 memset(&enrollee_info[empty_slot], 0, sizeof(struct enrollee_info));
944 memcpy(&enrollee_info[empty_slot], in, ENROLLEE_INFO_HDR_SIZE);
945 enrollee_info[empty_slot].rssi = in->rssi;
946 enrollee_info[empty_slot].state = ENR_IN_QUEUE;
947 enrollee_info[empty_slot].checkin_priority = 1; /* smaller means high pri */
948 enrollee_info[empty_slot].interval = REGISTRAR_TIMEOUT;
949 enrollee_info[empty_slot].checkin_timeout = REGISTRAR_TIMEOUT;
950 awss_debug("new enrollee[%d] dev_name:%s time:%x", empty_slot, in->dev_name,
951 os_get_time_ms());
952 enrollee_report();
953
954 return 0;
955 }
956
957 extern const uint8_t *cfg80211_find_vendor_ie(uint32_t oui, uint8_t oui_type,
958 const uint8_t *ies, int len);
959 /**
960 * @brief management frame handler
961 *
962 * @param[in] buffer @n 80211 raw frame or ie(information element) buffer
963 * @param[in] len @n buffer length
964 * @param[in] buffer_type @n 0 when buffer is a 80211 frame,
965 * 1 when buffer only contain IE info
966 * @return None.
967 * @see None.
968 * @note None.
969 */
awss_wifi_mgnt_frame_callback(uint8_t * buffer,int length,signed char rssi,int buffer_type)970 void awss_wifi_mgnt_frame_callback(uint8_t *buffer, int length,
971 signed char rssi, int buffer_type)
972 {
973 #define MGMT_BEACON (0x80)
974 #define MGMT_PROBE_REQ (0x40)
975 #define MGMT_PROBE_RESP (0x50)
976
977 /* fc(2) + dur(2) + da(6) + sa(6) + bssid(6) + seq(2) */
978 #define MGMT_HDR_LEN (24)
979
980 int type = buffer[0], len = 0, eid;
981 const uint8_t *ie;
982
983 if (buffer_type) {
984 ie = buffer;
985 goto ie_handler;
986 }
987
988 switch (type) {
989 case MGMT_BEACON:
990 /* awss_trace("beacon"); */
991 buffer += MGMT_HDR_LEN +
992 12; /* hdr(24) + 12(timestamp, beacon_interval, cap) */
993 length -= MGMT_HDR_LEN + 12;
994
995 eid = buffer[0];
996 len = buffer[1];
997 if (eid != 0) {
998 /* awss_warn("error eid, should be 0!"); */
999 return;
1000 }
1001
1002 /* skip ssid */
1003 buffer += 2;
1004 buffer += len;
1005 length -= len;
1006
1007 goto find_ie;
1008 break;
1009 case MGMT_PROBE_REQ:
1010 /* awss_trace("probe req\n"); */
1011 buffer += MGMT_HDR_LEN;
1012 length -= MGMT_HDR_LEN;
1013
1014 find_ie:
1015 ie = cfg80211_find_vendor_ie((uint32_t)WLAN_OUI_ALIBABA,
1016 (uint8_t)WLAN_OUI_TYPE_ENROLLEE,
1017 (const uint8_t *)buffer, (int)length);
1018 if (ie) {
1019 ie_handler:
1020 /* awss_trace("ie found to be processed\n"); */
1021 process_enrollee_ie(ie, rssi);
1022 }
1023 break;
1024 case MGMT_PROBE_RESP:
1025 /* awss_trace("probe resp"); */
1026 break;
1027 default:
1028 /* awss_trace("frame (%d): %02x\n", length, type); */
1029 break;
1030 }
1031 }
1032
1033 static uint8_t *registrar_frame;
1034 static int registrar_frame_len;
1035
registrar_raw_frame_init(struct enrollee_info * enr)1036 static void registrar_raw_frame_init(struct enrollee_info *enr)
1037 {
1038 int len, ie_len;
1039
1040 char passwd[OS_MAX_PASSWD_LEN + 1] = { 0 };
1041 char ssid[OS_MAX_SSID_LEN + 1] = { 0 };
1042 uint8_t bssid[OS_ETH_ALEN] = { 0 };
1043 int ssid_len, passwd_len;
1044
1045 HAL_Wifi_Get_Ap_Info(ssid, passwd, bssid);
1046 ssid_len = strlen(ssid);
1047 if (ssid_len > OS_MAX_SSID_LEN - 1) {
1048 ssid_len = OS_MAX_SSID_LEN - 1;
1049 }
1050
1051 passwd_len = strlen(passwd);
1052 if (passwd_len > OS_MAX_PASSWD_LEN - 1) {
1053 passwd_len = OS_MAX_PASSWD_LEN - 1;
1054 }
1055
1056 ie_len = ENROLLEE_SIGN_SIZE + ssid_len + passwd_len + REGISTRAR_IE_FIX_LEN;
1057 registrar_frame_len = sizeof(probe_req_frame) + ie_len;
1058
1059 registrar_frame = HAL_Malloc(registrar_frame_len);
1060 if (!registrar_frame) {
1061 awss_err("error: malloc size %d faild\r\n", registrar_frame_len);
1062 return;
1063 }
1064
1065 /* construct the registrar frame right now */
1066 len = sizeof(probe_req_frame) - FCS_SIZE;
1067 memcpy(registrar_frame, probe_req_frame, len);
1068
1069 registrar_frame[len++] = 221; /* vendor ie */
1070 registrar_frame[len++] = ie_len - 2; /* exclude 221 & len */
1071 registrar_frame[len++] = 0xD8;
1072 registrar_frame[len++] = 0x96;
1073 registrar_frame[len++] = 0xE0;
1074 registrar_frame[len++] = 0xAB; /* OUI type */
1075 registrar_frame[len++] = DEVICE_TYPE_VERSION; /* version & dev type */
1076 registrar_frame[len++] = enr->sign_len; /* dev signature len*/
1077 memcpy(®istrar_frame[len], enr->sign, enr->sign_len);
1078 len += enr->sign_len;
1079 registrar_frame[len++] = REGISTRAR_FRAME_TYPE; /* frame type */
1080
1081 registrar_frame[len++] = ssid_len;
1082 memcpy(®istrar_frame[len], ssid, ssid_len);
1083 len += ssid_len;
1084
1085 registrar_frame[len++] = passwd_len;
1086
1087 {
1088 p_Aes128_t aes = infra_aes128_init(&enr->key[0], enr->random,
1089 PLATFORM_AES_ENCRYPTION);
1090 infra_aes128_cfb_encrypt(aes, (uint8_t *)passwd, passwd_len,
1091 (uint8_t *)®istrar_frame[len]);
1092 infra_aes128_destroy(aes);
1093 }
1094
1095 len += passwd_len;
1096
1097 memcpy(®istrar_frame[len], bssid, ETH_ALEN);
1098 len += ETH_ALEN;
1099
1100 memcpy(®istrar_frame[len],
1101 &probe_req_frame[sizeof(probe_req_frame) - FCS_SIZE], FCS_SIZE);
1102
1103 /* update probe request frame src mac */
1104 os_wifi_get_mac(registrar_frame + SA_POS);
1105
1106 {
1107 /* dump registrar info */
1108 awss_debug("dump registrar info:");
1109 dump_hex(registrar_frame, registrar_frame_len, 16);
1110 }
1111 }
1112
registrar_raw_frame_destroy(void)1113 static void registrar_raw_frame_destroy(void)
1114 {
1115 if (registrar_frame_len) {
1116 HAL_Free(registrar_frame);
1117 registrar_frame = NULL;
1118 registrar_frame_len = 0;
1119 }
1120 }
1121
registrar_raw_frame_send(void)1122 static void registrar_raw_frame_send(void)
1123 {
1124 /* suppose registrar_frame was ready
1125 * @see enrollee_checkin()
1126 */
1127 int ret = HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, registrar_frame,
1128 registrar_frame_len);
1129 if (ret) {
1130 awss_warn("send failed");
1131 }
1132 }
1133
registar_yield()1134 int registar_yield()
1135 {
1136 #if (REGISTRAR_IDLE_DUTY > 0)
1137 registrar_schedule();
1138 #endif
1139 enrollee_checkin();
1140 return 0;
1141 }
1142 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
1143 }
1144 #endif
1145
1146 #endif
1147