1/*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <hi_stdlib.h>
17#include <at.h>
18#include <at_cmd.h>
19#include <at_parse.h>
20#include "hi_config.h"
21
22#include "stdio.h"
23#include "string.h"
24#include "malloc.h"
25#include "stdarg.h"
26#include "securec.h"
27
28#ifdef __cplusplus
29#if __cplusplus
30extern "C" {
31#endif
32#endif
33
34#define AT_SSID_MAX_LEN 32
35
36at_cmd_ctrl g_at_ctrl = {
37    .at_state = AT_IDLE,
38    .send_len = 0,
39    .trans_len = 0,
40    .is_first_recv_data = HI_TRUE,
41    .is_first_over_data = HI_TRUE,
42    .is_recv_end_char_flag = 0,
43};
44
45hi_u32 at_cmd_excute(const at_cmd_func *cmd_func, at_cmd_attr *cmd_parsed)
46{
47    hi_u32 ret;
48
49    if (cmd_func == HI_NULL || cmd_parsed == HI_NULL) {
50        return HI_ERR_FAILURE;
51    }
52
53    if (cmd_parsed->at_cmd_type == AT_CMD_TYPE_TEST) {
54        if (cmd_func->at_test_cmd) {
55            ret = cmd_func->at_test_cmd((hi_s32)cmd_parsed->at_param_cnt,
56                (const hi_char **)&cmd_parsed->param_array[0]);
57        } else {
58            at_printf("COMMAND TYPE NOT SUPPORT!\r\n");
59            ret = HI_ERR_FAILURE;
60            at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
61        }
62    } else if (cmd_parsed->at_cmd_type == AT_CMD_TYPE_QUERY) {
63        if (cmd_func->at_query_cmd) {
64            ret = cmd_func->at_query_cmd((hi_s32)cmd_parsed->at_param_cnt,
65                (const hi_char **)&cmd_parsed->param_array[0]);
66        } else {
67            at_printf("COMMAND TYPE NOT SUPPORT!\r\n");
68            ret = HI_ERR_FAILURE;
69            at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
70        }
71    } else if (cmd_parsed->at_cmd_type == AT_CMD_TYPE_SETUP) {
72        if (cmd_func->at_setup_cmd) {
73            ret = cmd_func->at_setup_cmd((hi_s32)cmd_parsed->at_param_cnt,
74                (const hi_char **)&cmd_parsed->param_array[0]);
75        } else {
76            at_printf("COMMAND TYPE NOT SUPPORT!\r\n");
77            ret = HI_ERR_FAILURE;
78            at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
79        }
80    } else if (cmd_parsed->at_cmd_type == AT_CMD_TYPE_EXE) {
81        if (cmd_func->at_exe_cmd) {
82            ret = cmd_func->at_exe_cmd((hi_s32)cmd_parsed->at_param_cnt,
83                (const hi_char **)&cmd_parsed->param_array[0]);
84        } else {
85            at_printf("COMMAND TYPE NOT SUPPORT!\r\n");
86            ret = HI_ERR_FAILURE;
87            at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
88        }
89    } else {
90        at_printf("COMMAND TYPE NOT SUPPORT!\r\n");
91        ret = HI_ERR_FAILURE;
92        at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
93    }
94
95    return ret;
96}
97
98static hi_void at_get_cmd_name(hi_char *cmd_line, at_cmd_attr *cmd_parsed)
99{
100    hi_s8 n = 0;
101
102    for (hi_u8 i = AT_CMD_MAX_LEN; i > 0; i--) {
103        if ((*cmd_line == '\0') || (*cmd_line == '=') || (*cmd_line == '?')) {
104            cmd_parsed->at_cmd_len = n;
105            return;
106        } else {
107            cmd_parsed->cmd_name[n] = *cmd_line;
108            cmd_line++;
109            n++;
110        }
111    }
112
113    cmd_parsed->at_cmd_len = -1;
114    memset_s(cmd_parsed->cmd_name, AT_CMD_MAX_LEN, 0, AT_CMD_MAX_LEN);
115}
116
117hi_u32 at_func_process(hi_char *out_cmd_line, at_cmd_attr *cmd_parsed)
118{
119    hi_u32 ret;
120    at_cmd_func *cmd_func = HI_NULL;
121    at_get_cmd_name(out_cmd_line, cmd_parsed);
122    if (cmd_parsed->at_cmd_len != (-1)) {
123        cmd_func = at_find_proc_func(cmd_parsed);
124    }
125
126    if (cmd_func != HI_NULL) {
127        ret = at_cmd_parse(out_cmd_line, cmd_parsed);
128        if (ret != HI_ERR_SUCCESS) {
129            at_printf("%s line: %d PARSE CMD FAIL!\r\n", __FUNCTION__, __LINE__);
130            return ret;
131        }
132
133        ret = at_cmd_excute(cmd_func, cmd_parsed);
134    } else {
135        ret = HI_ERR_FAILURE;
136        at_printf("%s line: %d COMMAND NOT SUPPORT!\r\n", __FUNCTION__, __LINE__);
137    }
138
139    return ret;
140}
141
142hi_u32 at_cmd_process(const hi_char *at_cmd_line)
143{
144    hi_u32 at_cmd_line_len;
145    hi_char *out_cmd_line = HI_NULL;
146    at_cmd_attr cmd_parsed = {0};
147    hi_u32 ret;
148
149    AT_ENTER;
150    if (at_cmd_line == HI_NULL) {
151        at_printf("INVALID NULL CMD!\r\n");
152        AT_RESPONSE_ERROR;
153        return HI_ERR_FAILURE;
154    }
155
156    at_cmd_line_len = (hi_u32)strlen(at_cmd_line) + 1;
157    out_cmd_line = (hi_char *)hi_malloc(HI_MOD_ID_SAL_DFX, at_cmd_line_len);
158    if (out_cmd_line == HI_NULL) {
159        at_printf("%s line%d NO ENOUGH MEMORY!\r\n", __FUNCTION__, __LINE__);
160        AT_RESPONSE_ERROR;
161        return HI_ERR_FAILURE;
162    }
163    memset_s(out_cmd_line, at_cmd_line_len, 0, at_cmd_line_len);
164
165    ret = (hi_u32)strncpy_s(out_cmd_line, at_cmd_line_len, at_cmd_line, at_cmd_line_len - 1);
166    if (ret != EOK) {
167        at_printf("%s,%d strncpy_s failed, err:%d!\n", __FUNCTION__, __LINE__, ret);
168        AT_RESPONSE_ERROR;
169        hi_free(HI_MOD_ID_SAL_DFX, out_cmd_line);
170        return HI_ERR_FAILURE;
171    }
172    out_cmd_line[at_cmd_line_len - 1] = '\0';
173
174    ret = at_func_process(out_cmd_line, &cmd_parsed);
175    if (ret != HI_ERR_SUCCESS && ret != HI_ERR_RECVING) {
176        at_printf("err at %s line: %d\n", __FUNCTION__, __LINE__);
177        AT_RESPONSE_ERROR;
178    } else if (ret == HI_ERR_RECVING) {
179        g_at_ctrl.at_state = AT_DATA_RECVING;
180    } else {
181        g_at_ctrl.at_state = AT_IDLE;
182    }
183
184    hi_free(HI_MOD_ID_SAL_DFX, out_cmd_line);
185    out_cmd_line = HI_NULL;
186
187    return ret;
188}
189
190hi_u32 at_param_null_check(hi_s32 argc, const hi_char **argv)
191{
192    for (hi_s32 i = 0; i < argc; i++) {
193        if (argv[i] == HI_NULL) {
194            return HI_ERR_FAILURE;
195        }
196    }
197    return HI_ERR_SUCCESS;
198}
199
200hi_u32 integer_check(const hi_char *val)
201{
202    hi_u32 len;
203    hi_u32 i;
204    hi_char *buf = (hi_char *)val;
205    if (buf == HI_NULL) {
206        return HI_ERR_FAILURE;
207    }
208    len = strlen(buf);
209    if ((*buf == '0') && (len != 1)) {
210        return HI_ERR_FAILURE;
211    }
212    for (i = 0; i < len; i++) {
213        if ((*buf < '0') || (*buf > '9')) {
214            return HI_ERR_FAILURE;
215        }
216        buf++;
217    }
218    return HI_ERR_SUCCESS;
219}
220
221static hi_u32 at_check_mac_elem(const hi_char elem)
222{
223    if (elem >= '0' && elem <= '9') {
224        return HI_ERR_SUCCESS;
225    } else if (elem >= 'A' && elem <= 'F') {
226        return HI_ERR_SUCCESS;
227    } else if (elem >= 'a' && elem <= 'f') {
228        return HI_ERR_SUCCESS;
229    } else if (elem == ':') {
230        return HI_ERR_SUCCESS;
231    }
232
233    return HI_ERR_FAILURE;
234}
235
236hi_u32 cmd_strtoaddr(const hi_char *param, hi_uchar *mac_addr, hi_u32 addr_len)
237{
238    hi_u32 cnt;
239    hi_char *tmp1 = (hi_char *)param;
240    hi_char *tmp2 = NULL;
241    hi_char *tmp3 = NULL;
242
243    for (cnt = 0; cnt < 17; cnt++) {    /* 17 */
244        if (at_check_mac_elem(param[cnt]) != HI_ERR_SUCCESS) {
245            return HI_ERR_FAILURE;
246        }
247    }
248
249    for (cnt = 0; cnt < (addr_len - 1); cnt++) {
250        tmp2 = (char*)strsep(&tmp1, ":");
251        if (tmp2 == NULL) {
252            return HI_ERR_APP_INVALID_PARAMETER;
253        }
254        mac_addr[cnt] = (hi_uchar)strtoul(tmp2, &tmp3, 16); /* 16 */
255    }
256
257    if (tmp1 == NULL) {
258        return HI_ERR_APP_INVALID_PARAMETER;
259    }
260    mac_addr[cnt] = (hi_uchar)strtoul(tmp1, &tmp3, 16); /* 16 */
261    return HI_ERR_SUCCESS;
262}
263
264char *at_strrchr(const char *src, int c)
265{
266    return strrchr(src, c);
267}
268
269void *at_malloc(size_t size)
270{
271    if (size > 4096) {  /* max alloc mem 4096 */
272        return NULL;
273    }
274    void *ptr = malloc(size);
275    return ptr;
276}
277
278void at_free(char *ptr)
279{
280    if (ptr) {
281        free(ptr);
282    }
283}
284
285size_t at_strlen(const char *src)
286{
287    return strlen(src);
288}
289
290int at_pading(char *str, size_t size, const char *format, ...)
291{
292    va_list ap = NULL;
293    int ret;
294
295    va_start(ap, format);
296    ret = vsnprintf_s(str, AT_SSID_MAX_LEN * 4 + 1, size, format, ap); /* 4 length */
297    va_end(ap);
298    if (size > 0) {
299        str[size - 1] = '\0';
300    }
301    return ret;
302}
303
304char* at_dup_binstr(const char *src, size_t len)
305{
306    char *res = NULL;
307    int ret;
308
309    if (src == NULL) {
310        return NULL;
311    }
312    res = at_malloc(len + 1);
313    if (res == NULL) {
314        return NULL;
315    }
316    ret = memcpy_s(res, len, src, len);
317    if (ret != EOK) {
318        at_free(res);
319        res = NULL;
320        return NULL;
321    }
322    res[len] = '\0';
323
324    return res;
325}
326
327static int at_hex2num(char c)
328{
329    if (c >= '0' && c <= '9') {
330        return c - '0';
331    }
332    if (c >= 'a' && c <= 'f') {
333        return c - 'a' + 10;    /* add 10 */
334    }
335    if (c >= 'A' && c <= 'F') {
336        return c - 'A' + 10;    /* add 10 */
337    }
338    return -1;
339}
340
341int at_hex2byte(const char *hex)
342{
343    int a, b;
344    a = at_hex2num(*hex++);
345    if (a < 0) {
346        return -1;
347    }
348    b = at_hex2num(*hex++);
349    if (b < 0) {
350        return -1;
351    }
352    return ((hi_u32)a << 4) | (hi_u32)b;    /* 4 */
353}
354
355/**
356 * at_hexstr2bin - Convert ASCII hex string into binary data
357 * @hex: ASCII hex string (e.g., "01ab")
358 * @buf: Buffer for the binary data
359 * @len: Length of the text to convert in bytes (of buf); hex will be double
360 * this size
361 * Returns: 0 on success, -1 on failure (invalid hex string)
362 */
363int at_hexstr2bin(const char *hex, hi_u8 *buf, size_t len)
364{
365    size_t i;
366    const char *ipos = hex;
367    hi_u8 *opos = buf;
368
369    for (i = 0; i < len; i++) {
370        int a = at_hex2byte(ipos);
371        if (a < 0) {
372            return -1;
373        }
374        *opos++ = a;
375        ipos += 2;  /* add 2 */
376    }
377    return 0;
378}
379
380void at_printf_encode(char *txt, size_t maxlen, const hi_u8 *data, size_t len)
381{
382    char *end = txt + maxlen;
383    size_t i;
384
385    for (i = 0; i < len; i++) {
386        if (txt + 4 >= end) {   /* add 4 */
387            break;
388        }
389
390        switch (data[i]) {
391            case '\"':
392                *txt++ = '\\';
393                *txt++ = '\"';
394                break;
395            case '\\':
396                *txt++ = '\\';
397                *txt++ = '\\';
398                break;
399            case '\033':
400                *txt++ = '\\';
401                *txt++ = 'e';
402                break;
403            case '\n':
404                *txt++ = '\\';
405                *txt++ = 'n';
406                break;
407            case '\r':
408                *txt++ = '\\';
409                *txt++ = 'r';
410                break;
411            case '\t':
412                *txt++ = '\\';
413                *txt++ = 't';
414                break;
415            default:
416                if (data[i] >= 32 && data[i] <= 126) {  /* range [32,126] */
417                    *txt++ = data[i];
418                } else {
419                    txt += at_pading(txt, end - txt, "\\x%02x", data[i]);
420                }
421                break;
422        }
423    }
424
425    *txt = '\0';
426}
427
428hi_void at_printf_decode_slash(hi_u8 *buf, const char **str_pos, size_t *str_len)
429{
430    const char *pos = *str_pos;
431    size_t len = *str_len;
432    int val;
433
434    pos++;
435    switch (*pos) {
436        case '\\':
437            buf[len++] = '\\';
438            pos++;
439            break;
440        case '"':
441            buf[len++] = '"';
442            pos++;
443            break;
444        case 'n':
445            buf[len++] = '\n';
446            pos++;
447            break;
448        case 'r':
449            buf[len++] = '\r';
450            pos++;
451            break;
452        case 't':
453            buf[len++] = '\t';
454            pos++;
455            break;
456        case 'e':
457            buf[len++] = '\033';
458            pos++;
459            break;
460        case 'x':
461            pos++;
462            val = at_hex2byte(pos);
463            if (val < 0) {
464                val = at_hex2num(*pos);
465                if (val < 0) {
466                    break;
467                }
468                buf[len++] = val;
469                pos++;
470            } else {
471                buf[len++] = val;
472                pos += 2;   /* add 2 */
473            }
474            break;
475        case '0':
476        case '1':
477        case '2':
478        case '3':
479        case '4':
480        case '5':
481        case '6':
482        case '7':
483            val = *pos++ - '0';
484            if (*pos >= '0' && *pos <= '7') {
485                val = val * 8 + (*pos++ - '0'); /* 8 */
486            }
487            if (*pos >= '0' && *pos <= '7') {
488                val = val * 8 + (*pos++ - '0'); /* 8 */
489            }
490            buf[len++] = val;
491            break;
492        default:
493            break;
494    }
495
496    *str_pos = pos;
497    *str_len = len;
498}
499
500size_t at_printf_decode(hi_u8 *buf, size_t maxlen, const char *str)
501{
502    const char *pos = str;
503    size_t len = 0;
504
505    while (*pos) {
506        if (len + 1 >= maxlen) {
507            break;
508        }
509        switch (*pos) {
510            case '\\':
511                at_printf_decode_slash(buf, &pos, &len);
512                break;
513            default:
514                buf[len++] = *pos++;
515                break;
516        }
517    }
518    if (maxlen > len) {
519        buf[len] = '\0';
520    }
521
522    return len;
523}
524
525char* at_parse_string_normal(const char *value, size_t *len)
526{
527    const char *pos = NULL;
528    char *str = NULL;
529
530    value++;
531    pos = at_strrchr(value, '"');
532    if (pos == NULL || pos[1] != '\0') {
533        return NULL;
534    }
535    *len = pos - value;
536    str = at_dup_binstr(value, *len);
537    if (str == NULL) {
538        return NULL;
539    }
540    return str;
541}
542
543char* at_parse_string_with_p(const char *value, size_t *len)
544{
545    const char *pos = NULL;
546    char *tstr = NULL;
547    char *str = NULL;
548    size_t tlen;
549
550    value += 2;     /* add 2 */
551    pos = at_strrchr(value, '"');
552    if (pos == NULL || pos[1] != '\0') {
553        return NULL;
554    }
555    tlen = pos - value;
556    tstr = at_dup_binstr(value, tlen);
557    if (tstr == NULL) {
558        return NULL;
559    }
560
561    str = at_malloc(tlen + 1);
562    if (str == NULL) {
563        at_free(tstr);
564        return NULL;
565    }
566
567    *len = at_printf_decode((hi_u8 *) str, tlen + 1, tstr);
568    at_free(tstr);
569
570    return str;
571}
572
573char* at_parse_string_other(const char *value, size_t *len)
574{
575    hi_u8 *str = NULL;
576    size_t tlen;
577    size_t hlen = at_strlen(value);
578    if (hlen & 1) {
579        return NULL;
580    }
581    tlen = hlen / 2;    /* 2 */
582    str = at_malloc(tlen + 1);
583    if (str == NULL) {
584        return NULL;
585    }
586    if (at_hexstr2bin(value, str, tlen)) {
587        at_free((char*)str);
588        return NULL;
589    }
590    str[tlen] = '\0';
591    *len = tlen;
592    return (char *) str;
593}
594
595
596char* at_parse_string(const char *value, size_t *len)
597{
598    if (len == HI_NULL) {
599        return HI_NULL;
600    }
601    if (*value == '"') {
602        return at_parse_string_normal(value, len);
603    } else if (*value == 'P' && value[1] == '"') {
604        return at_parse_string_with_p(value, len);
605    } else {
606        return at_parse_string_other(value, len);
607    }
608}
609
610/**
611 * at_ssid_txt - Convert SSID to a printable string
612 * @ssid: SSID (32-octet string)
613 * @ssid_len: Length of ssid in octets
614 * Returns: Pointer to a printable string
615 *
616 * This function can be used to convert SSIDs into printable form. In most
617 * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
618 * does not limit the used character set, so anything could be used in an SSID.
619 *
620 * This function uses a static buffer, so only one call can be used at the
621 * time, i.e., this is not re-entrant and the returned buffer must be used
622 * before calling this again.
623 */
624const char* at_ssid_txt(const hi_u8 *ssid, size_t ssid_len)
625{
626    static char ssid_txt[AT_SSID_MAX_LEN * 4 + 1]; /* 4 */
627
628    if (ssid == NULL) {
629        ssid_txt[0] = '\0';
630        return ssid_txt;
631    }
632
633    at_printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
634    return ssid_txt;
635}
636
637#ifdef __cplusplus
638#if __cplusplus
639    }
640#endif
641#endif
642