1 /*
2 * Copyright (c) 2021 Chipsea Technologies (Shenzhen) Corp., Ltd. All rights reserved.
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 #include <stdlib.h>
16 #include "al_rtos.h"
17 #include "wifi_mac.h"
18 #include "wifi_host.h"
19 #include "wifi_host_wpa.h"
20 #include "wifi_host_cntrl.h"
21 #include "wifi_host_config.h"
22 #include "wifi_host_iperf.h"
23 #include "dbg_assert.h"
24 #include "rwnx_utils.h"
25 #include "wifi_nx_msg_tx.h"
26 #include "porting_net_al.h"
27 #include "console.h"
28 #include "wlan_if.h"
29 #include "command.h"
30 #include "wifi_host_tx.h"
31 #include "fhost_command_common.h"
32
33 /// Console task message queue size
34 #define FHOST_CONSOLE_QUEUE_SIZE 10
35
36 /*
37 * GLOBAL VARIABLES
38 ****************************************************************************************
39 */
40 /// Master message queue
41 static rtos_queue console_queue;
42
43 /// Link to control task
44 static struct fhost_cntrl_link *console_cntrl_link;
45
46 /**
47 ****************************************************************************************
48 * @brief Convert string containing ip address
49 *
50 * The string may should be of the form a.b.c.d/e (/e being optional)
51 *
52 * @param[in] str String to parse
53 * @parse[out] ip Updated with the numerical value of the ip address
54 * @parse[out] mask Updated with the numerical value of the network mask
55 * (or 32 if not present)
56 * @return 0 if string contained what looks like a valid ip address and -1 otherwise
57 ****************************************************************************************
58 */
fhost_network_parse_ip4(char * str,uint32_t * ip,uint32_t * mask)59 static int fhost_network_parse_ip4(char *str, uint32_t *ip, uint32_t *mask)
60 {
61 char *token;
62 uint32_t a, i, j;
63
64 #define check_is_num(_str) for (j = 0 ; j < strlen(_str); j++) { \
65 if (_str[j] < '0' || _str[j] > '9') \
66 return -1; \
67 }
68
69 // Check if mask is present
70 token = strchr(str, '/');
71 if (token && mask) {
72 *token++ = '\0';
73 check_is_num(token);
74 a = atoi(token);
75 if (a == 0 || a > 32)
76 return -1;
77 *mask = (1<<a) - 1;
78 }
79 else if (mask)
80 {
81 *mask = 0xffffffff;
82 }
83
84 // parse the ip part
85 *ip = 0;
86 for (i = 0; i < 4; i ++)
87 {
88 if (i < 3)
89 {
90 token = strchr(str, '.');
91 if (!token)
92 return -1;
93 *token++ = '\0';
94 }
95 check_is_num(str);
96 a = atoi(str);
97 if (a > 255)
98 return -1;
99 str = token;
100 *ip += (a << (i * 8));
101 }
102
103 return 0;
104 }
105
106 /**
107 ****************************************************************************************
108 * @brief Find the interface index
109 *
110 * @param[in] name Name of the interace
111 * @return Index of the FHOST wifi interface or -1 if interface doesn't exist.
112 ****************************************************************************************
113 */
fhost_console_search_itf(char * name)114 static int fhost_console_search_itf(char *name)
115 {
116 int fhost_vif_idx = fhost_vif_idx_from_name(name);
117
118 if (fhost_vif_idx >= 0)
119 return fhost_vif_idx;
120
121 dbg("Cannot find interface %s\n", name);
122 return -1;
123 }
124
125 #if NX_FHOST_MONITOR
126 /**
127 ****************************************************************************************
128 * @brief callback function
129 *
130 * Extract received packet informations (frame length, type, mac addr ...) in monitor mode
131 *
132 * @param[in] info RX Frame information.
133 * @param[in] arg Not used
134 ****************************************************************************************
135 */
fhost_console_monitor_cb(struct fhost_frame_info * info,void * arg)136 static void fhost_console_monitor_cb(struct fhost_frame_info *info, void *arg)
137 {
138 if (info->payload == NULL) {
139 dbg("Unsupported frame: length = %d\r\n", info->length);
140 } else {
141 struct mac_hdr *hdr = (struct mac_hdr *)info->payload;
142 uint8_t *adr1 = ((uint8_t *)(hdr->addr1.array));
143 uint8_t *adr2 = ((uint8_t *)(hdr->addr2.array));
144 uint8_t *adr3 = ((uint8_t *)(hdr->addr3.array));
145 dbg("a1=%02x:%02x:%02x:%02x:%02x:%02x a2=%02x:%02x:%02x:%02x:%02x:%02x "
146 "a3=%02x:%02x:%02x:%02x:%02x:%02x fc=%04X SN:%d len=%d\n",
147 adr1[0], adr1[1], adr1[2], adr1[3], adr1[4], adr1[5],
148 adr2[0], adr2[1], adr2[2], adr2[3], adr2[4], adr2[5],
149 adr3[0], adr3[1], adr3[2], adr3[3], adr3[4], adr3[5],
150 hdr->fctl, hdr->seq >> 4, info->length);
151 }
152 }
153 #endif /* NX_FHOST_MONITOR */
154
155 #if PLF_IPERF
do_iperf(int argc,char * argv[])156 static int do_iperf (int argc, char *argv[])
157 {
158 char iperf_params[128] = {0};
159 unsigned int idx = 0, j = 0;
160
161 if ((argc < 1)) {
162 dbg ("Usage:\n iperf <-s|-c|-h> [options]\n");
163 return 1;
164 }
165
166 if (!netif_is_up(net_if_find_from_wifi_idx(fhost_vif_idx))) {
167 dbg ("Usage:\n Connect AP first\n");
168 return 1;
169 }
170
171 memcpy(&(iperf_params[idx]), argv[1], strlen(argv[1]));
172 idx += strlen(argv[1]);
173
174 if(strstr(iperf_params, "stop")) {
175 fhost_iperf_sigkill_handler(iperf_task_handle);
176 return 0;
177 }
178
179 j = 3;
180 while(j <= argc) {
181 iperf_params[idx] = ' ';
182 idx ++;
183 memcpy(&(iperf_params[idx]), argv[j - 1], strlen(argv[j - 1]));
184 idx += strlen(argv[j - 1]);
185 j++;
186 }
187
188 fhost_console_iperf(iperf_params);
189
190 return 0;
191 }
192 #endif /* PLF_IPERF */
193 #if PLF_PING
do_ping(int argc,char * argv[])194 static int do_ping (int argc, char *argv[])
195 {
196 char ping_params[64] = {0};
197 unsigned int idx = 0, j = 0;
198 if ((argc < 2)) {
199 dbg ("Usage:\n ping dst_ip|stop ID\n");
200 return 1;
201 }
202
203 if (!netif_is_up(net_if_find_from_wifi_idx(fhost_vif_idx))) {
204 dbg ("Usage:\n Connect first\n");
205 return 1;
206 }
207
208 memcpy(&(ping_params[idx]), argv[1], strlen(argv[1]));
209 idx += strlen(argv[1]);
210 j = 3;
211 while(j <= argc) {
212 ping_params[idx] = ' ';
213 idx ++;
214 memcpy(&(ping_params[idx]), argv[j - 1], strlen(argv[j - 1]));
215 idx += strlen(argv[j - 1]);
216 j++;
217 }
218
219 fhost_console_ping(ping_params);
220
221 return 0;
222 }
223 #endif /* PLF_PING */
224
225
226 /**
227 ****************************************************************************************
228 * @brief Process function for 'scan' command
229 *
230 * @param[in] params Not used
231 * @return 0 on success and !=0 if error occurred
232 ****************************************************************************************
233 */
do_scan(int argc,char * argv[])234 static int do_scan(int argc, char *argv[])
235 {
236 int nb_res;
237 struct mac_scan_result result;
238 unsigned int fvif_idx;
239
240 if (argc < 2) {
241 return -1;
242 }
243
244 fvif_idx = console_cmd_strtoul(argv[1], NULL, 10);
245 if (fvif_idx >= NX_VIRT_DEV_MAX) {
246 dbg("invalid fvif index\n");
247 return -2;
248 }
249 ipc_host_cntrl_start();
250
251 console_cntrl_link = fhost_cntrl_cfgrwnx_link_open();
252 if (console_cntrl_link == NULL) {
253 dbg(D_ERR "Failed to open link with control task\n");
254 ASSERT_ERR(0);
255 }
256 // Reset STA interface (this will end previous wpa_supplicant task)
257 if (fhost_set_vif_type(console_cntrl_link, fvif_idx, VIF_UNKNOWN, false) ||
258 fhost_set_vif_type(console_cntrl_link, fvif_idx, VIF_STA, false)) {
259
260 fhost_cntrl_cfgrwnx_link_close(console_cntrl_link);
261 return -1;
262 }
263
264 nb_res = fhost_scan(console_cntrl_link, fvif_idx, NULL);
265 dbg("Got %d scan results\n", nb_res);
266
267 nb_res = 0;
268 while(fhost_get_scan_results(console_cntrl_link, nb_res++, 1, &result)) {
269 result.ssid.array[result.ssid.length] = '\0'; // set ssid string ending
270 dbg("(%3d dBm) CH=%3d BSSID=%02x:%02x:%02x:%02x:%02x:%02x SSID=%s,group_cipher=%d,pairwise_cipher=%d\n",
271 (int8_t)result.rssi, phy_freq_to_channel(result.chan->band, result.chan->freq),
272 ((uint8_t *)result.bssid.array)[0], ((uint8_t *)result.bssid.array)[1],
273 ((uint8_t *)result.bssid.array)[2], ((uint8_t *)result.bssid.array)[3],
274 ((uint8_t *)result.bssid.array)[4], ((uint8_t *)result.bssid.array)[5],
275 (char *)result.ssid.array,result.group_cipher,result.pairwise_cipher);
276 }
277
278 fhost_cntrl_cfgrwnx_link_close(console_cntrl_link);
279 return 0;
280 }
281
282 /**
283 ****************************************************************************************
284 * @brief Process function for 'status' command
285 *
286 * @param[in] params Optional command parameter
287 * Valid parameter: "chan", "vif"
288 *
289 * @return FHOST_IPC_SUCCESS on success and FHOST_IPC_ERROR if error occurred
290 ****************************************************************************************
291 */
do_status(int argc,char * argv[])292 static int do_status(int argc, char *argv[])
293 {
294 struct fhost_status status;
295 bool show_vif = true, show_chan = true;
296 int i;
297
298 if (argc > 1) {
299 if (!strncmp("vif", argv[1], 3))
300 show_chan = false;
301 else if (!strncmp("chan", argv[1], 4))
302 show_vif = false;
303 else {
304 dbg("invalid subcmd\n");
305 return -1;
306 }
307 }
308
309 fhost_get_status(&status);
310
311 if (show_chan) {
312 const struct mac_chan_def *chan_def;
313 dbg("Available Channels:\n");
314
315 for (chan_def = &(status.chan_2g4[0]), i = 0;
316 i < (status.chan_2g4_cnt + status.chan_5g_cnt);
317 chan_def++, i++) {
318 if (i == status.chan_2g4_cnt)
319 chan_def = &(status.chan_5g[0]);
320
321 dbg("ch: %3d, freq: %dMhz, TX pwr: %2d dBm, flags: %s%s\n",
322 phy_freq_to_channel(chan_def->band, chan_def->freq),
323 chan_def->freq, chan_def->tx_power,
324 chan_def->flags & CHAN_NO_IR ? "[NO_IR]" : "",
325 chan_def->flags & CHAN_DISABLED ? "[DISABLED]" : "");
326 }
327 dbg("\n");
328 }
329
330 if (show_vif) {
331 for (i = 0; i < status.vif_max_cnt; i++) {
332 struct fhost_vif_status vif_status;
333 char vif_name[4];
334 fhost_get_vif_status(i, &vif_status);
335 memset(vif_name, 0, sizeof(vif_name));
336 fhost_vif_name(i, vif_name, sizeof(vif_name) - 1);
337 dbg("[%d] %s: MAC=%02x:%02x:%02x:%02x:%02x:%02x ",
338 i, vif_name[0] ? vif_name : "nul",
339 vif_status.mac_addr[0], vif_status.mac_addr[1],
340 vif_status.mac_addr[2], vif_status.mac_addr[3],
341 vif_status.mac_addr[4], vif_status.mac_addr[5]);
342 switch (vif_status.type) {
343 case VIF_STA:
344 dbg("STA");
345 break;
346 case VIF_IBSS:
347 dbg("IBSS");
348 break;
349 case VIF_AP:
350 dbg("AP");
351 break;
352 case VIF_MESH_POINT:
353 dbg("MESH");
354 break;
355 case VIF_MONITOR:
356 dbg("MONITOR");
357 break;
358 default:
359 dbg("INACTIVE\n");
360 break;
361 }
362 if (vif_status.type != VIF_UNKNOWN) {
363 if (vif_status.chan.prim20_freq != 0) {
364 dbg(", Operating Channel: %dMHz@%dMHz\n",
365 vif_status.chan.prim20_freq,
366 (1 << vif_status.chan.type) * 20);
367 } else {
368 dbg(", No Operating Channel\n");
369 }
370 }
371 }
372 }
373
374 return 0;
375 }
376
377 /**
378 ****************************************************************************************
379 * @brief Process function for 'ip' command
380 *
381 * ip command can be used for.
382 * - address managing:
383 @verbatim
384 ip show [itf-name]
385 ip add <ip>/<mask> [gw] <itf-name>
386 ip del <itf-name>
387 @endverbatim
388 *
389 * @param[in] params Port number
390 * @return 0 on success and !=0 if error occurred
391 ****************************************************************************************
392 */
do_ip(int argc,char * argv[])393 static int do_ip(int argc, char *argv[])
394 {
395 int fhost_vif_idx = -1;
396 if (argc < 2) {
397 dbg("wrong # of args\n");
398 return -1;
399 }
400 if (!strcmp("show", argv[1])) {
401 int i = 0;
402 int i_end = NX_VIRT_DEV_MAX;
403 if (argc > 2) {
404 fhost_vif_idx = fhost_console_search_itf(argv[2]);
405 if (fhost_vif_idx < 0) {
406 dbg("invalid itf\r\n");
407 return -2;
408 }
409 i = fhost_vif_idx;
410 i_end = fhost_vif_idx + 1;
411 }
412 for (; i < i_end; i++) {
413 char ifname[NET_AL_MAX_IFNAME];
414 char *state, *connected;
415 struct fhost_vif_ip_addr_cfg ip_cfg;
416 uint32_t ip, gw;
417 const uint8_t *mac_addr;
418
419 if (fhost_env.vif[i].mac_vif &&
420 (fhost_env.vif[i].mac_vif->type != VIF_UNKNOWN)) {
421 state = "UP";
422 if (fhost_env.vif[i].mac_vif->active)
423 connected = ",CONNECTED";
424 else
425 connected = "";
426 } else {
427 state = "DOWN";
428 connected = "";
429 }
430 mac_addr = net_if_get_mac_addr(fhost_to_net_if(i));
431
432 if (fhost_vif_name(i, ifname, NET_AL_MAX_IFNAME) < 0)
433 return -3;
434
435 if (fhost_get_vif_ip(i, &ip_cfg))
436 return -4;
437
438 ip = ip_cfg.ipv4.addr;
439 gw = ip_cfg.ipv4.gw;
440 dbg("[%d] %s: MAC=%02x:%02x:%02x:%02x:%02x:%02x ip=%d.%d.%d.%d/%d gw=%d.%d.%d.%d %s%s\n", i, ifname[0] ? ifname : "nul",
441 mac_addr[0], mac_addr[1], mac_addr[2],
442 mac_addr[3], mac_addr[4], mac_addr[5],
443 ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff,
444 32 - co_clz(ip_cfg.ipv4.mask),
445 gw & 0xff, (gw >> 8) & 0xff, (gw >> 16) & 0xff, (gw >> 24) & 0xff,
446 state, connected);
447 }
448 } else if (!strcmp("add", argv[1])) {
449 struct fhost_vif_ip_addr_cfg ip_cfg;
450 char *ip_str, *gw_str = NULL, *itf = NULL;
451
452 memset(&ip_cfg, 0, sizeof(ip_cfg));
453 ip_str = argv[2];
454 if (argc == 4) {
455 itf = argv[3];
456 } else if (argc > 4) {
457 gw_str = argv[3];
458 itf = argv[4];
459 }
460
461 fhost_vif_idx = fhost_console_search_itf(itf);
462 if (fhost_vif_idx < 0) {
463 return -5;
464 }
465
466 ip_cfg.mode = IP_ADDR_STATIC_IPV4;
467 if (fhost_network_parse_ip4(ip_str, &ip_cfg.ipv4.addr, &ip_cfg.ipv4.mask)) {
468 return -6;
469 }
470 if (gw_str && fhost_network_parse_ip4(gw_str, &ip_cfg.ipv4.gw, NULL)) {
471 return -7;
472 }
473 if (fhost_set_vif_ip(fhost_vif_idx, &ip_cfg))
474 return -8;
475 dbg("add ip=%s gw=%s itf=%s\r\n",ip_str, gw_str ? gw_str : "null", itf);
476 } else if (!strcmp("del", argv[1])) {
477 struct fhost_vif_ip_addr_cfg ip_cfg;
478 char *itf = argv[2];
479 fhost_vif_idx = fhost_console_search_itf(itf);
480 if (fhost_vif_idx < 0)
481 return -9;
482
483 ip_cfg.mode = IP_ADDR_NONE;
484 fhost_set_vif_ip(fhost_vif_idx, &ip_cfg);
485 dbg("del itf=%s\r\n", itf);
486 } else {
487 dbg("invalid subcmd\n");
488 }
489 return 0;
490 }
491
fhost_nw_upper(char * str,char * stop)492 static void fhost_nw_upper(char *str, char *stop)
493 {
494 char *ptr = str;
495 char c;
496
497 if (stop)
498 {
499 c = *stop;
500 *stop = 0;
501 }
502 while (*ptr)
503 {
504 if ((*ptr >= 'a') && (*ptr <= 'z'))
505 *ptr -= 'a' - 'A';
506 ptr++;
507 }
508
509 if (stop)
510 *stop = c;
511 }
512 static struct fhost_cntrl_link *sta_link;
513
514 #if NX_BEACONING
515 static struct fhost_cntrl_link *ap_link;
516 #include "dhcps.h"
517 #endif
518 /**
519 ****************************************************************************************
520 * @brief Process function for 'ap' command
521 *
522 * Start an AP
523 * @verbatim
524 ap [-i <itf>] -s <SSID> -f <freq>[+-@] [-a <akm>[,<akm 2>]] [-k <key>]
525 [-b bcn_int[,dtim_period]] [-u <unicast cipher>[,<unicast cipher 2>]]
526 [-g <group cipher>] [-m <mfp: 0|1|2>]
527 @endverbatim
528 * The '+/-' after the frequency allow to configure a 40MHz channel with the secondary
529 * channel being the upper/lower one. The '@' allow to configure a 80 MHz channel, this
530 * is only allowed for valid primary channel and center freq is automatically computed.
531 *
532 * @param[in] params Connection parameters
533 * @return 0 on success and !=0 if error occurred
534 ****************************************************************************************
535 */
do_ap(int argc,char * argv[])536 int do_ap (int argc, char *argv[])
537 {
538 #if NX_BEACONING
539 char ap_params[256] = {0};
540 unsigned int idx = 0, j = 0;
541 struct fhost_vif_ap_cfg cfg;
542 int fhost_vif_idx = 0;//fhost_search_first_valid_itf();
543
544 if ((argc < 1)) {
545 dbg("Usage:\n ap \n");
546 return ERR_WRONG_ARGS;
547 }
548
549 j = 2;
550 while(j <= argc) {
551 memcpy(&(ap_params[idx]), argv[j - 1], strlen(argv[j - 1]));
552 idx += strlen(argv[j - 1]);
553 ap_params[idx] = ' ';
554 idx ++;
555 j++;
556 }
557
558 char *token, *next = ap_params;
559 memset(&cfg, 0, sizeof(cfg));
560
561 while ((token = fhost_nw_next_token(&next)))
562 {
563 char option;
564
565 if ((token[0] != '-') | (token[2] != '\0'))
566 return ERR_WRONG_ARGS;
567
568 option = token[1];
569 token = fhost_nw_next_token(&next);
570 if (!token)
571 return ERR_WRONG_ARGS;
572
573 switch(option)
574 {
575 #if 0
576 case 'i':
577 {
578 fhost_vif_idx = fhost_search_itf(token);
579 if (fhost_vif_idx < 0)
580 return ERR_CMD_FAIL;
581 break;
582 }
583 #endif
584 case 's':
585 {
586 size_t ssid_len = strlen(token);
587 if (ssid_len > sizeof(cfg.ssid.array))
588 {
589 dbg("Invalid SSID\r\n");
590 return ERR_CMD_FAIL;
591 }
592
593 memcpy(cfg.ssid.array, token, ssid_len);
594 cfg.ssid.length = ssid_len;
595 break;
596 }
597 case 'k':
598 {
599 size_t key_len = strlen(token);
600 if ((key_len + 1) > sizeof(cfg.key))
601 {
602 dbg("Invalid Key\r\n");
603 return ERR_CMD_FAIL;
604 }
605 strcpy(cfg.key, token);
606 break;
607 }
608 case 'f':
609 {
610 int len = strlen(token) - 1;
611 struct mac_chan_def *chan = NULL;
612 int offset = 0;
613 if (token[len] == '+')
614 {
615 token[len] = 0;
616 offset = 10;
617 cfg.chan.type = PHY_CHNL_BW_40;
618 }
619 else if (token[len] == '-')
620 {
621 token[len] = 0;
622 offset = -10;
623 cfg.chan.type = PHY_CHNL_BW_40;
624 }
625 else if (token[len] == '@')
626 {
627 token[len] = 0;
628 cfg.chan.type = PHY_CHNL_BW_80;
629 }
630 else
631 {
632 cfg.chan.type = PHY_CHNL_BW_20;
633 }
634
635 cfg.chan.prim20_freq = atoi(token);
636 chan = fhost_chan_get(cfg.chan.prim20_freq);
637 if (!chan)
638 {
639 dbg("Invalid channel\n");
640 return ERR_CMD_FAIL;
641 }
642
643 if (cfg.chan.prim20_freq >= PHY_FREQ_5G)
644 cfg.chan.band = PHY_BAND_5G;
645 else
646 cfg.chan.band = PHY_BAND_2G4;
647
648 if (cfg.chan.type == PHY_CHNL_BW_80)
649 {
650 if ((cfg.chan.prim20_freq < 5180) ||
651 (cfg.chan.prim20_freq > 5805))
652 {
653 dbg("Invalid primary for 80MHz channel\n");
654 return ERR_CMD_FAIL;
655 }
656 offset = (cfg.chan.prim20_freq - 5180) % 80;
657 if (offset < 20)
658 offset = 30;
659 else if (offset < 40)
660 offset = 10;
661 else if (offset < 60)
662 offset = -10;
663 else
664 offset = -30;
665 }
666 cfg.chan.center1_freq = cfg.chan.prim20_freq + offset;
667 break;
668 }
669 case 'a':
670 {
671 char *next_akm;
672 fhost_nw_upper(token, NULL);
673 next_akm = strchr(token, ',');
674 while (token)
675 {
676 if (strncmp(token, "OPEN", 4) == 0)
677 {
678 cfg.akm |= CO_BIT(MAC_AKM_NONE);
679 }
680 else if (strncmp(token, "WEP", 4) == 0)
681 {
682 cfg.akm |= CO_BIT(MAC_AKM_PRE_RSN);
683 }
684 else if (strncmp(token, "WPA", 3) == 0)
685 {
686 cfg.akm |= CO_BIT(MAC_AKM_PRE_RSN) | CO_BIT(MAC_AKM_PSK);
687 }
688 else if (strncmp(token, "RSN", 3) == 0)
689 {
690 cfg.akm |= CO_BIT(MAC_AKM_PSK);
691 }
692 else if (strncmp(token, "SAE", 3) == 0)
693 {
694 cfg.akm |= CO_BIT(MAC_AKM_SAE);
695 }
696 else
697 {
698 dbg("The following AKM are supported [%s]:\n"
699 "OPEN: For open AP\n"
700 "WEP: For AP with WEP security\n"
701 "WPA: For AP with WPA/PSK security (pre WPA2)\n"
702 "RSN: For AP with WPA2/PSK security\n"
703 "SAE: For AP with WPA3/PSK security\n", token);
704 if (strncmp(token, "HELP", 4) == 0)
705 return ERR_NONE;
706 else
707 return ERR_CMD_FAIL;
708 }
709
710 token = next_akm;
711 if (token)
712 {
713 token++;
714 next_akm = strchr(token, ',');
715 }
716 }
717 break;
718 }
719 case 'u':
720 case 'g':
721 {
722 char *next_cipher;
723 uint32_t cipher = 0;
724
725 fhost_nw_upper(token, NULL);
726 next_cipher = strchr(token, ',');
727 while (token)
728 {
729 if (strncmp(token, "CCMP", 4) == 0)
730 {
731 cipher |= CO_BIT(MAC_CIPHER_CCMP);
732 }
733 else if (strncmp(token, "TKIP", 4) == 0)
734 {
735 cipher |= CO_BIT(MAC_CIPHER_TKIP);
736 }
737 else if (strncmp(token, "WEP40", 5) == 0)
738 {
739 cipher |= CO_BIT(MAC_CIPHER_WEP40);
740 }
741 else if (strncmp(token, "WEP104", 6) == 0)
742 {
743 cipher |= CO_BIT(MAC_CIPHER_WEP104);
744 }
745 else if (strncmp(token, "SMS4", 4) == 0)
746 {
747 cipher |= CO_BIT(MAC_CIPHER_WPI_SMS4);
748 }
749 else
750 {
751 dbg("The following cipher are supported [%s]:\n"
752 "CCMP, TKIP, WEP40, WEP104, SMS4", token);
753 if (strncmp(token, "HELP", 4) == 0)
754 return ERR_NONE;
755 else
756 return ERR_CMD_FAIL;
757 }
758
759 token = next_cipher;
760 if (token)
761 {
762 token++;
763 next_cipher = strchr(token, ',');
764 }
765 }
766
767 if (option == 'u')
768 cfg.unicast_cipher = cipher;
769 else
770 cfg.group_cipher = cipher;
771
772 break;
773 }
774 case 'b':
775 {
776 char *dtim = strchr(token, ',');
777 if (dtim)
778 {
779 *dtim++ = 0;
780 cfg.dtim_period = atoi(dtim);
781 }
782 cfg.bcn_interval = atoi(token);
783
784 break;
785 }
786 case 'm':
787 {
788 cfg.mfp = atoi(token);
789 break;
790 }
791 case 'h':
792 {
793 cfg.hidden_ssid = atoi(token);
794 break;
795 }
796 default:
797 {
798 dbg("Invalid option %c\n", option);
799 return ERR_WRONG_ARGS;
800 }
801 }
802 }
803
804 if (fhost_vif_idx < 0)
805 return ERR_CMD_FAIL;
806
807 if ((cfg.ssid.length == 0) || (cfg.chan.prim20_freq == 0))
808 return ERR_WRONG_ARGS;
809
810 // try to select the best AKM if not set
811 if (cfg.akm == 0)
812 {
813 if (strlen(cfg.key) == 0)
814 cfg.akm = CO_BIT(MAC_AKM_NONE);
815 else if (strlen(cfg.key) == 5)
816 cfg.akm = CO_BIT(MAC_AKM_PRE_RSN);
817 else
818 cfg.akm = CO_BIT(MAC_AKM_PSK);
819 }
820 ipc_host_cntrl_start();
821
822 struct fhost_vif_tag *fhost_vif;
823
824 ap_link = fhost_cntrl_cfgrwnx_link_open();
825 if (ap_link == NULL) {
826 dbg(D_ERR "Failed to open link with control task\n");
827 ASSERT_ERR(0);
828 }
829
830 // (Re)Set interface type to AP
831 if (fhost_set_vif_type(ap_link, fhost_vif_idx, VIF_UNKNOWN, false) ||
832 fhost_set_vif_type(ap_link, fhost_vif_idx, VIF_AP, false))
833 return ERR_CMD_FAIL;
834
835 fhost_cntrl_cfgrwnx_link_close(ap_link);
836
837 fhost_vif = &fhost_env.vif[fhost_vif_idx];
838 MAC_ADDR_CPY(&(vif_info_tab[fhost_vif_idx].mac_addr), &(fhost_vif->mac_addr));
839
840 if (fhost_ap_cfg(fhost_vif_idx, &cfg))
841 {
842 dbg("Failed to start AP, check your configuration");
843 return ERR_CMD_FAIL;
844 }
845
846 net_if_t *net_if = fhost_to_net_if(fhost_vif_idx);
847 if (net_if == NULL) {
848 dbg("[CS] net_if_find_from_wifi_idx fail\r\n");
849 return 1;
850 }
851 uint32_t ip_mask = 0x00FFFFFF;
852 uint32_t ip_addr = get_ap_ip_addr();
853 net_if_set_ip(net_if, ip_addr, ip_mask, 0);
854
855 //set up DHCP server
856 dhcpServerStart(net_if);
857
858 // Now that we got an IP address use this interface as default
859 net_if_set_default(net_if);
860
861 fhost_tx_task_init();
862 dbg("DHCPS init: ip=%d.%d.%d.%d\r\n",
863 (ip_addr)&0xFF, (ip_addr>>8)&0xFF, (ip_addr>>16)&0xFF, (ip_addr>>24)&0xFF);
864
865 #endif // NX_BEACONING
866
867
868 return ERR_NONE;
869 }
870
871 /**
872 ****************************************************************************************
873 * @brief Convert string containing MAC address
874 *
875 * The string may should be of the form xx:xx:xx:xx:xx:xx
876 *
877 * @param[in] str String to parse
878 * @param[out] addr Updated with MAC address
879 * @return 0 if string contained what looks like a valid MAC address and -1 otherwise
880 ****************************************************************************************
881 */
fhost_nw_parse_mac_addr(char * str,struct mac_addr * addr)882 static int fhost_nw_parse_mac_addr(char *str, struct mac_addr *addr)
883 {
884 char *ptr = str;
885 uint32_t i;
886
887 if (!str || strlen(str) < 17 || !addr)
888 return -1;
889
890 for (i = 0 ; i < 6 ; i++)
891 {
892 char *next;
893 long int hex = strtol(ptr, &next, 16);
894 if (((unsigned)hex > 255) || ((hex == 0) && (next == ptr)) ||
895 ((i < 5) && (*next != ':')) ||
896 ((i == 5) && (*next != '\0')))
897 return -1;
898
899 ((uint8_t *)addr)[i] = (uint8_t)hex;
900 ptr = ++next;
901 }
902
903 return 0;
904 }
905
do_sta(int argc,char * argv[])906 int do_sta (int argc, char *argv[])
907 {
908 char sta_params[256] = {0};
909 unsigned int idx = 0, j = 0;
910 int fhost_vif_idx = 0;//fhost_search_first_valid_itf();
911 struct fhost_vif_sta_cfg cfg;
912 net_if_t *net_if = NULL;
913
914 if ((argc < 1)) {
915 dbg("Usage:\n ap \n");
916 return ERR_WRONG_ARGS;
917 }
918
919 j = 2;
920 while(j <= argc) {
921 memcpy(&(sta_params[idx]), argv[j - 1], strlen(argv[j - 1]));
922 idx += strlen(argv[j - 1]);
923 sta_params[idx] = ' ';
924 idx ++;
925 j++;
926 }
927 char *token, *next = sta_params;
928
929 memset(&cfg, 0, sizeof(cfg));
930
931 cfg.timeout_ms = 30000;
932 while ((token = fhost_nw_next_token(&next)))
933 {
934 char option;
935
936 if ((token[0] != '-') | (token[2] != '\0'))
937 return ERR_WRONG_ARGS;
938
939 option = token[1];
940 token = fhost_nw_next_token(&next);
941 if (!token)
942 return ERR_WRONG_ARGS;
943
944 switch(option)
945 {
946 #if 0
947 case 'i':
948 {
949 cfg.fhost_vif_idx = fhost_search_itf(token);
950 if (cfg.fhost_vif_idx < 0)
951 return FHOST_IPC_ERROR;
952 break;
953 }
954 #endif
955 case 's':
956 {
957 size_t ssid_len = strlen(token);
958 if (ssid_len > sizeof(cfg.ssid.array))
959 {
960 dbg("Invalid SSID\r\n");
961 return ERR_CMD_FAIL;
962 }
963
964 memcpy(cfg.ssid.array, token, ssid_len);
965 cfg.ssid.length = ssid_len;
966
967 break;
968 }
969 case 'b':
970 {
971 if (fhost_nw_parse_mac_addr(token, &cfg.bssid))
972 {
973 dbg("Invalid BSSID\r\n");
974 return ERR_CMD_FAIL;
975 }
976 break;
977 }
978 case 'k':
979 {
980 size_t key_len = strlen(token);
981 if ((key_len + 1) > sizeof(cfg.key))
982 {
983 dbg("Invalid Key\r\n");
984 return ERR_CMD_FAIL;
985 }
986 strcpy(cfg.key, token);
987 break;
988 }
989 case 'f':
990 {
991 unsigned int i;
992 char *next_freq = strchr(token, ',');
993 for (i = 0 ; i < CO_ARRAY_SIZE(cfg.freq); i++)
994 {
995 cfg.freq[i] = atoi(token);
996 if (!next_freq)
997 break;
998 *next_freq++ = '\0';
999 token = next_freq;
1000 next_freq = strchr(token, ',');
1001 }
1002 break;
1003 }
1004 case 'a':
1005 {
1006 char *next_akm;
1007 fhost_nw_upper(token, NULL);
1008 next_akm = strchr(token, ',');
1009 while (token)
1010 {
1011 if (strncmp(token, "OPEN", 4) == 0)
1012 {
1013 cfg.akm |= CO_BIT(MAC_AKM_NONE);
1014 }
1015 else if (strncmp(token, "WEP", 4) == 0)
1016 {
1017 cfg.akm |= CO_BIT(MAC_AKM_NONE);
1018 }
1019 else if (strncmp(token, "PSK", 3) == 0)
1020 {
1021 cfg.akm |= CO_BIT(MAC_AKM_PSK);
1022 }
1023 else if (strncmp(token, "SAE", 3) == 0)
1024 {
1025 cfg.akm |= CO_BIT(MAC_AKM_SAE);
1026 }
1027 else
1028 {
1029 dbg("The following AKM are supported [%s]:\n"
1030 "OPEN: For open AP\n"
1031 "WEP: For AP configured with WEP\n"
1032 "PSK: For AP configured with a password and WPA/WPA2\n"
1033 "SAE: For AP configured with a password and WPA3\n", token);
1034 if (strncmp(token, "HELP", 4) == 0)
1035 return ERR_NONE;
1036 else
1037 return ERR_CMD_FAIL;
1038 }
1039
1040 token = next_akm;
1041 if (token)
1042 {
1043 token++;
1044 next_akm = strchr(token, ',');
1045 }
1046 }
1047 break;
1048 }
1049 case 't':
1050 {
1051 cfg.timeout_ms = atoi(token);
1052 break;
1053 }
1054 default:
1055 return ERR_WRONG_ARGS;
1056 }
1057 }
1058
1059 if (cfg.ssid.length == 0)
1060 return ERR_WRONG_ARGS;
1061 ipc_host_cntrl_start();
1062
1063 sta_link = fhost_cntrl_cfgrwnx_link_open();
1064 if (sta_link == NULL) {
1065 dbg(D_ERR "Failed to open link with control task\n");
1066 ASSERT_ERR(0);
1067 }
1068
1069 // Reset STA interface (this will end previous wpa_supplicant task)
1070 if (fhost_set_vif_type(sta_link, fhost_vif_idx, VIF_UNKNOWN, false) ||
1071 fhost_set_vif_type(sta_link, fhost_vif_idx, VIF_STA, false))
1072 return ERR_CMD_FAIL;
1073 fhost_cntrl_cfgrwnx_link_close(sta_link);
1074
1075 if (fhost_sta_cfg(fhost_vif_idx, &cfg))
1076 return ERR_CMD_FAIL;
1077
1078 // Get the first network interface (created by CNTRL task).
1079 net_if = net_if_find_from_wifi_idx(fhost_vif_idx);
1080 if (net_if == NULL) {
1081 dbg("[CS] net_if_find_from_wifi_idx fail\r\n");
1082 return 1;
1083 }
1084
1085 // Start DHCP client to retrieve ip address
1086 if (wlan_dhcp(net_if)) {
1087 wlan_disconnect_sta((uint8_t)fhost_vif_idx);
1088 dbg("[CS] dhcp fail\r\n");
1089 return 3;
1090 }
1091
1092 // Now that we got an IP address use this interface as default
1093 net_if_set_default(net_if);
1094
1095 return ERR_NONE;
1096 }
1097
do_set_deepsleep_param(int argc,char * argv[])1098 int do_set_deepsleep_param (int argc, char *argv[])
1099 {
1100 unsigned int listen_interval = console_cmd_strtoul(argv[1], NULL, 10);
1101
1102 set_deepsleep_param(listen_interval, 1);
1103
1104 return ERR_NONE;
1105 }
1106
1107 #ifdef CFG_PRERELEASE_CODE
1108 #include "fhost_console_prerelease.c"
1109 #endif
1110
fhost_command_add(void)1111 static void fhost_command_add(void)
1112 {
1113 RWNX_DBG(RWNX_FN_ENTRY_STR);
1114
1115 #if NX_BEACONING
1116 console_cmd_add("startap", " startap band ssid <pwd>", 4, do_start_ap);
1117 console_cmd_add("stopap", " stopap", 1, do_stop_ap);
1118 console_cmd_add("runap", " runap -s <SSID> -f <freq>[+-@] [-a <akm>[,<akm 2>]] [-k <key>] "
1119 "[-b bcn_int[,dtim_period]] [-m <mfp: 0|1|2>] "
1120 "[-u <unicast cipher>[,<unicast cipher 2>]] [-g <group cipher>] [-m <mfp: 0|1|2>] [-h hidden]", 20, do_ap);
1121 #endif /* NX_BEACONING */
1122 console_cmd_add("runsta", " runsta -s <SSID> [-k <key>] [-b <bssid>] "
1123 "[-f <freq>[,freq]] [-a <akm>] [-t <timeout>]", 20, do_sta);
1124 console_cmd_add("connect_wep", " connect_wep 0/1 ssid <pwd>", 4, do_connect_wep);
1125 console_cmd_add("connect", " connect 0/1 ssid <pwd>", 4, do_connect);
1126 console_cmd_add("mac", " mac ?/[hex_str]", 2, do_mac);
1127 console_cmd_add("setdsparam", " setdsparam listen_interval", 4, do_set_deepsleep_param);
1128 console_cmd_add("clrfi", " clr flash info", 1, do_restore);
1129 #if NX_WPS
1130 console_cmd_add("wps", " wps", 1, do_wps_pbc);
1131 #endif /* NX_WPS */
1132 console_cmd_add("disconnect", " disconnect", 1, do_disconnect);
1133 #if PLF_PING
1134 console_cmd_add("ping", " ping dst_ip|stop ID", 20, do_ping);
1135 #endif /* PLF_PING */
1136 #if PLF_IPERF
1137 console_cmd_add("iperf", " iperf <-s|-c|-h> [options]", 20, do_iperf);
1138 #endif /* PLF_IPERF */
1139
1140 console_cmd_add("scan", " scan fvif_idx", 2, do_scan);
1141 console_cmd_add("status", " status [chan|vif]", 2, do_status);
1142 console_cmd_add("ip", " ip show [itf]\n"
1143 " ip add <ip>/<mask> [gw] <itf>\n"
1144 " ip del <itf>", 5, do_ip);
1145 #if NX_SMARTCONFIG
1146 console_cmd_add("smartconf", " smartconf", 1, do_smartconf);
1147 console_cmd_add("stopsc", " stopsc", 1, do_stop_smartconf);
1148 #endif /* NX_SMARTCONFIG */
1149 #ifdef CFG_PRERELEASE_CODE
1150 fhost_prerelease_command_add();
1151 #endif
1152 }
1153
1154 /**
1155 ****************************************************************************************
1156 * @brief Request the RTOS to resume the console task.
1157 * This function sends a msg to console_queue to realize the resume.
1158 * Note that currently this function is supposed to be called from interrupt.
1159 *
1160 * @param[in] isr Indicates if called from ISR
1161 ****************************************************************************************
1162 */
fhost_console_resume(bool isr)1163 static void fhost_console_resume(bool isr)
1164 {
1165 int res;
1166 struct fhost_msg msg;
1167
1168 msg.id = FHOST_MSG_ID(FHOST_MSG_CONSOLE, 0);
1169 msg.len = 0;
1170 msg.data = NULL;
1171
1172 res = rtos_queue_write(console_queue, &msg, 0, isr);
1173 ASSERT_ERR(res == 0);
1174 }
1175
1176 /**
1177 ****************************************************************************************
1178 * @brief console task implementation.
1179 ****************************************************************************************
1180 */
RTOS_TASK_FCT(fhost_console_task)1181 static RTOS_TASK_FCT(fhost_console_task)
1182 {
1183 struct fhost_msg msg;
1184
1185 if (wlan_connected) {
1186 fhost_sta_recover_connection();
1187 }
1188
1189 for (;;) {
1190 rtos_queue_read(console_queue, &msg, -1, false);
1191
1192 switch (FHOST_MSG_TYPE(msg.id)) {
1193 case FHOST_MSG_CONSOLE:
1194 console_schedule();
1195 break;
1196 default:
1197 break;
1198 }
1199 }
1200 }
1201
1202 #if CFG_APP_CONSOLEWIFI
fhost_application_init(void)1203 int fhost_application_init(void)
1204 {
1205 RWNX_DBG(RWNX_FN_ENTRY_STR);
1206
1207 // Initialize console
1208 console_init();
1209
1210 // Create the console task
1211 if (rtos_task_create(fhost_console_task, "CONSOLE", APPLICATION_TASK,
1212 2048, NULL, RTOS_TASK_PRIORITY(1), NULL)) {
1213 return 1;
1214 }
1215
1216 if (rtos_queue_create(sizeof(struct fhost_msg), FHOST_CONSOLE_QUEUE_SIZE, &console_queue))
1217 return 2;
1218
1219 console_ntf_register(fhost_console_resume);
1220
1221 fhost_command_add();
1222
1223 return 0;
1224 }
1225 #else
1226 // If NOT define CFG_APP_CONSOLEWIFI, define a stub function.
fhost_application_init(void)1227 int fhost_application_init(void)
1228 {
1229 return 0;
1230 }
1231 #endif
1232