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(&registrar_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(&registrar_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 *)&registrar_frame[len]);
1092         infra_aes128_destroy(aes);
1093     }
1094 
1095     len += passwd_len;
1096 
1097     memcpy(&registrar_frame[len], bssid, ETH_ALEN);
1098     len += ETH_ALEN;
1099 
1100     memcpy(&registrar_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