• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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