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
30 extern "C" {
31 #endif
32 #endif
33
34 #define AT_SSID_MAX_LEN 32
35
36 at_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
at_cmd_excute(const at_cmd_func * cmd_func,at_cmd_attr * cmd_parsed)45 hi_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
at_get_cmd_name(hi_char * cmd_line,at_cmd_attr * cmd_parsed)98 static 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
at_func_process(hi_char * out_cmd_line,at_cmd_attr * cmd_parsed)117 hi_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
at_cmd_process(const hi_char * at_cmd_line)142 hi_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
at_param_null_check(hi_s32 argc,const hi_char ** argv)190 hi_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
integer_check(const hi_char * val)200 hi_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
at_check_mac_elem(const hi_char elem)221 static 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
cmd_strtoaddr(const hi_char * param,hi_uchar * mac_addr,hi_u32 addr_len)236 hi_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
at_strrchr(const char * src,int c)264 char *at_strrchr(const char *src, int c)
265 {
266 return strrchr(src, c);
267 }
268
at_malloc(size_t size)269 void *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
at_free(char * ptr)278 void at_free(char *ptr)
279 {
280 if (ptr) {
281 free(ptr);
282 }
283 }
284
at_strlen(const char * src)285 size_t at_strlen(const char *src)
286 {
287 return strlen(src);
288 }
289
at_pading(char * str,size_t size,const char * format,...)290 int 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
at_dup_binstr(const char * src,size_t len)304 char* 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
at_hex2num(char c)327 static 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
at_hex2byte(const char * hex)341 int 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 */
at_hexstr2bin(const char * hex,hi_u8 * buf,size_t len)363 int 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
at_printf_encode(char * txt,size_t maxlen,const hi_u8 * data,size_t len)380 void 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
at_printf_decode_slash(hi_u8 * buf,const char ** str_pos,size_t * str_len)428 hi_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
at_printf_decode(hi_u8 * buf,size_t maxlen,const char * str)500 size_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
at_parse_string_normal(const char * value,size_t * len)525 char* 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
at_parse_string_with_p(const char * value,size_t * len)543 char* 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
at_parse_string_other(const char * value,size_t * len)573 char* 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
at_parse_string(const char * value,size_t * len)596 char* 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 */
at_ssid_txt(const hi_u8 * ssid,size_t ssid_len)624 const 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