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