From d27ca03b6cf94cfed39a271f46d8cbb17ae3650e Mon Sep 17 00:00:00 2001 From: liqinhui Date: Mon, 26 Jun 2023 19:18:32 +0800 Subject: [PATCH] wifi/simdriver: Support the sim wifi. Add the Sim WiFi function, which can provide the wifi operating on nuttx sim emulator, and support two modes that simulate wifi, HWSIM and RNC(real network card). - In the HWSIM mode, we simulates two wlan interfaces. The wlan0 is STA and the wlan1 is AP. The wlan0 can connect to the wlan1 in the nuttx simulator. - In the RNC mode, we can use the same wlan interface name on the nuttx simulator to control the connection behavior of the real wireless card. Signed-off-by: liqinhui --- arch/sim/Kconfig | 12 +- arch/sim/src/Makefile | 4 + arch/sim/src/sim/sim_internal.h | 4 + arch/sim/src/sim/sim_netdriver.c | 30 +- arch/sim/src/sim/sim_wifidriver.c | 1490 +++++++++++++++++++++++ drivers/net/Kconfig | 2 +- tools/simwifi/README | 115 ++ tools/simwifi/dnsmasq.conf | 8 + tools/simwifi/hostapd.conf | 14 + tools/simwifi/hostapd_hwsim.conf | 14 + tools/simwifi/sim_wifi.sh | 576 +++++++++ tools/simwifi/udhcpc.script | 40 + tools/simwifi/wpa_supplicant.conf | 2 + tools/simwifi/wpa_supplicant_hwsim.conf | 10 + 14 files changed, 2317 insertions(+), 4 deletions(-) create mode 100644 arch/sim/src/sim/sim_wifidriver.c create mode 100644 tools/simwifi/README create mode 100644 tools/simwifi/dnsmasq.conf create mode 100644 tools/simwifi/hostapd.conf create mode 100644 tools/simwifi/hostapd_hwsim.conf create mode 100755 tools/simwifi/sim_wifi.sh create mode 100644 tools/simwifi/udhcpc.script create mode 100644 tools/simwifi/wpa_supplicant.conf create mode 100644 tools/simwifi/wpa_supplicant_hwsim.conf diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 05d379f627..ed410099db 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -223,13 +223,23 @@ config SIM_NETDEV_NUMBER int "Number of Simulated Network Device" default 1 range 1 8 - depends on SIM_NETDEV_TAP + depends on SIM_NETDEV ---help--- The number of simulated network devices. Note that only one network device will be brought up by netinit automatically, others will be kept in DOWN state by default. +config SIM_WIFIDEV_NUMBER + int "Number of Simulated WiFi Device" + default 0 + range 0 SIM_NETDEV_NUMBER + depends on SIM_NETDEV && DRIVERS_IEEE80211 && NETDEV_WIRELESS_HANDLER + ---help--- + The number of simulated wifi network devices. + + Note that only one network device will be brought up by netinit automatically, + others will be kept in DOWN state by default. endif config SIM_NETDEV_VPNKIT_PATH diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index b0864ea26b..5750fd5fe7 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -179,6 +179,10 @@ ifeq ($(CONFIG_FS_FAT),y) STDLIBS += -lz endif +ifneq ($(CONFIG_SIM_WIFIDEV_NUMBER),0) + CFLAGS += -DTOPDIR=\"$(TOPDIR)\" +endif + ifeq ($(CONFIG_SIM_NETDEV_TAP),y) CSRCS += sim_netdriver.c ifneq ($(CONFIG_WINDOWS_CYGWIN),y) diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 057c337eec..151273dc8d 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -60,6 +60,10 @@ # define CONFIG_SIM_NETDEV_NUMBER 1 #endif +#ifndef CONFIG_SIM_WIFIDEV_NUMBER +# define CONFIG_SIM_WIFIDEV_NUMBER 0 +#endif + /* Determine which (if any) console driver to use */ #ifndef CONFIG_DEV_CONSOLE diff --git a/arch/sim/src/sim/sim_netdriver.c b/arch/sim/src/sim/sim_netdriver.c index d932955a60..b467275947 100644 --- a/arch/sim/src/sim/sim_netdriver.c +++ b/arch/sim/src/sim/sim_netdriver.c @@ -86,6 +86,9 @@ #define DEVIDX(p) ((struct sim_netdev_s *)(p) - g_sim_dev) #define DEVBUF(p) (((struct sim_netdev_s *)(p))->buf) +#if CONFIG_SIM_WIFIDEV_NUMBER != 0 +# include "sim_wifidriver.c" +#else /**************************************************************************** * Private Types ****************************************************************************/ @@ -95,6 +98,7 @@ struct sim_netdev_s struct netdev_lowerhalf_s dev; uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */ }; +#endif /**************************************************************************** * Private Function Prototypes @@ -188,7 +192,21 @@ static int netdriver_ifup(struct netdev_lowerhalf_s *dev) #else /* CONFIG_NET_IPv6 */ sim_netdev_ifup(DEVIDX(dev), &dev->netdev.d_ipv6addr); #endif /* CONFIG_NET_IPv4 */ - netdev_lower_carrier_on(dev); + +#if CONFIG_SIM_WIFIDEV_NUMBER != 0 + if (DEVIDX(dev) < CONFIG_SIM_WIFIDEV_NUMBER) + { + if (wifidriver_connected(dev)) + { + netdev_lower_carrier_on(dev); + } + } + else +#endif + { + netdev_lower_carrier_on(dev); + } + return OK; } @@ -236,11 +254,19 @@ int sim_netdriver_init(void) dev->quota[NETPKT_RX] = 1; dev->ops = &g_ops; +#if CONFIG_SIM_WIFIDEV_NUMBER != 0 + if (devidx < CONFIG_SIM_WIFIDEV_NUMBER) + { + wifidriver_init(dev, devidx); + } +#endif + /* Register the device with the OS so that socket IOCTLs can be * performed */ - netdev_lower_register(dev, NET_LL_ETHERNET); + netdev_lower_register(dev, devidx < CONFIG_SIM_WIFIDEV_NUMBER ? + NET_LL_IEEE80211 : NET_LL_ETHERNET); } return OK; diff --git a/arch/sim/src/sim/sim_wifidriver.c b/arch/sim/src/sim/sim_wifidriver.c new file mode 100644 index 0000000000..3681e5e7f5 --- /dev/null +++ b/arch/sim/src/sim/sim_wifidriver.c @@ -0,0 +1,1490 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_wifidriver.c + * Manage the host wireless + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "sim_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CMD_LEN 512 +#define BUF_LEN 1024 +#define SSID_MAX_LEN 33 + +/* ESSID flags */ + +#define IW_ESSID_OFF 0 /* Disconnect with access point */ +#define IW_ESSID_ON 1 /* Connect with access point */ + +#define IEEE80211_CAP_PRIVACY 0x0010 +#define WLAN_EID_SSID 0 + +#define IW_EV_LEN(field) \ + (offsetof(struct iw_event, u) + sizeof(((union iwreq_data *)0)->field)) + +#define WPA_CTRL_PATH " -p /var/run/simwifi/wpa_supplicant " +#define WPA_CLI "/usr/bin/sudo /usr/sbin/wpa_cli " + +#define HOSTAPD_CTRL_PATH " -p /var/run/simwifi/hostapd " +#define HOSTAPD_CLI "/usr/bin/sudo /usr/sbin/hostapd_cli " +#define SIMWIFI_FILE "tools/simwifi/sim_wifi.sh " + +#define WPA_SET_NETWORK(wifidev, fmt, args...) \ + set_cmd(wifidev,"set_network %d "fmt, (wifidev)->network_id, ##args) + +#define get_cmd(wifidev, buf, buf_size, fmt, ...) \ + ({ \ + int ret_; \ + if (wifidev->mode == IW_MODE_INFRA) \ + { \ + ret_ = host_system(buf, buf_size, "%s %s -i wlan%d "fmt, WPA_CLI, \ + WPA_CTRL_PATH, wifidev->devidx, ##__VA_ARGS__); \ + } \ + else if (wifidev->mode == IW_MODE_MASTER) \ + { \ + ret_ = host_system(buf, buf_size, "%s %s -i wlan%d "fmt, HOSTAPD_CLI, \ + HOSTAPD_CTRL_PATH, wifidev->devidx, ##__VA_ARGS__); \ + } \ + else \ + { \ + ret_ = -EINVAL; \ + } \ + ret_; \ + }) + +#define set_cmd(wifidev, fmt, ...) \ + ({ \ + char rbuf[BUF_LEN]; \ + int ret__ = -EINVAL; \ + if (get_cmd(wifidev, rbuf, BUF_LEN, fmt, ##__VA_ARGS__) > 0) \ + { \ + if (!strncmp(rbuf, "OK", 2)) \ + { \ + ninfo(fmt" is OK\n", ##__VA_ARGS__); \ + ret__ = 0; \ + } \ + else if (!strncmp(rbuf, "FAIL", 4)) \ + { \ + nerr("ERROR: "fmt" is failed!\n", ##__VA_ARGS__); \ + ret__ = -EINVAL; \ + } \ + } \ + ret__; \ + }) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sim_scan_result_s +{ + int total_len; + int cur_len; + char *buf; /* iwr->u.data.pointer */ +}; + +struct sim_bss_info_s +{ + uint32_t version; /* version field */ + uint32_t length; /* byte length of data in this record, */ + /* starting at version and including IEs */ + struct ether_addr BSSID; + uint16_t beacon_period; /* units are Kusec */ + uint16_t capability; /* Capability information */ + uint8_t ssid_len; + uint8_t ssid[32]; + struct + { + uint32_t count; /* rates in this set */ + uint8_t rates[16]; /* rates in 500kbps units w/hi bit set if + * basic */ + } rateset; /* supported rates */ + uint16_t atim_window; /* units are Kusec */ + uint8_t dtim_period; /* DTIM period */ + int16_t RSSI; /* receive signal strength (in dBm) */ + int8_t phy_noise; /* noise (in dBm) */ + + uint8_t n_cap; /* BSS is 802.11N Capable */ + uint32_t nbss_cap; /* 802.11N BSS Capabilities (based on * + * HT_CAP_*) */ + uint32_t freq; /* 802.11N BSS frequency */ + uint8_t ctl_ch; /* 802.11N BSS control channel number */ + uint32_t reserved32[1]; /* Reserved for expansion of BSS * + * properties */ + uint8_t flags; /* flags */ + uint8_t reserved[3]; /* Reserved for expansion of BSS * + * properties */ + uint8_t basic_mcs[16]; /* 802.11N BSS required MCS set */ + + uint16_t ie_offset; /* offset at which IEs start, from * + * beginning */ + uint32_t ie_length; /* byte length of Information Elements */ + int16_t snr; /* average SNR of during frame reception */ +}; + +struct sim_netdev_s +{ + struct netdev_lowerhalf_s dev; + uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */ + char ssid[SSID_MAX_LEN]; + char bssid[ETH_ALEN]; + uint16_t channel; + uint32_t freq; + uint8_t password[64]; + int key_mgmt; + int proto; + int auth_alg; + int pairwise_chiper; + int group_cipher; + uint8_t mode; /* IW_MODE_INFRA/ IW_MODE_MASTER */ + uint32_t bitrate; + uint8_t txpower; + char country[4]; + int8_t sensitivity; + uint8_t devidx; + bool psk_flag; /* for psk, 0: unset, 1: set */ + char host_ifname[IFNAMSIZ]; /* The wlan interface name on the host */ + uint8_t network_id; /* for sta, default is 0 */ +}; + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int wifidriver_connect(struct netdev_lowerhalf_s *dev); +static int wifidriver_disconnect(struct netdev_lowerhalf_s *dev); +static int wifidriver_essid(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_bssid(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_passwd(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_mode(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_auth(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_freq(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_bitrate(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_txpower(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_country(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_sensitivity(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_scan(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set); +static int wifidriver_range(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct wireless_ops_s g_iw_ops = +{ + wifidriver_connect, + wifidriver_disconnect, + wifidriver_essid, + wifidriver_bssid, + wifidriver_passwd, + wifidriver_mode, + wifidriver_auth, + wifidriver_freq, + wifidriver_bitrate, + wifidriver_txpower, + wifidriver_country, + wifidriver_sensitivity, + wifidriver_scan, + wifidriver_range +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int get_cmd_result_num(struct sim_netdev_s *wifidev, char *cmd) +{ + int num = 0; + char rbuf[BUF_LEN]; + + if (get_cmd(wifidev, rbuf, BUF_LEN, "%s", cmd) > 0) + { + num = atoi(rbuf); + } + else + { + nerr("ERROR: Failed to get num.\n"); + num = -EINVAL; + } + + return num; +} + +/* For sta, add an available network. */ + +static int wpa_add_network(struct sim_netdev_s *wifidev) +{ + return get_cmd_result_num(wifidev, "add_network"); +} + +/* For sta, get the number of available networks. */ + +static int wpa_get_network_num(struct sim_netdev_s *wifidev) +{ + return get_cmd_result_num(wifidev, "list_network | grep \"\\[\" | wc -l"); +} + +/* For sta, get the available network_id. */ + +static int wpa_get_last_network_id(struct sim_netdev_s *wifidev, + int network_num) +{ + int num; + int i = 0; + char rbuf[BUF_LEN]; + + num = get_cmd(wifidev, rbuf, BUF_LEN, "%s", + "list_network | grep \"\\[\" | awk '{print $1}'"); + if (num > 0) + { + while (--network_num) + { + if (rbuf[i] == '\n') + { + i++; + } + + while (rbuf[i] != '\n') + { + i++; + } + } + + num = atoi(rbuf + i); + } + else + { + nerr("ERROR: Failed to get the last network ID."); + } + + return num; +} + +static const char *get_auth_algstr(uint32_t auth_alg) +{ + switch (auth_alg) + { + case IW_ENCODE_ALG_TKIP: + case IW_ENCODE_ALG_CCMP: + return "OPEN"; + default: + nerr("ERROR: Failed to transfer wireless auth alg: %u", auth_alg); + return NULL; + } +} + +static const char *get_authstr(int auth) +{ + switch (auth) + { + case IW_AUTH_WPA_VERSION_DISABLED: + return NULL; + + case IW_AUTH_WPA_VERSION_WPA: + return "WPA"; + + case IW_AUTH_WPA_VERSION_WPA2: + return "RSN"; + default: + nerr("ERROR: Failed to transfer wifi auth: %d", auth); + return NULL; + } +} + +static const char *get_cipherstr(int cipher) +{ + switch (cipher) + { + case IW_AUTH_CIPHER_NONE: + return "NONE"; + + case IW_AUTH_CIPHER_WEP40: + return "WEP40"; + + case IW_AUTH_CIPHER_WEP104: + return "WEP104"; + + case IW_AUTH_CIPHER_TKIP: + return "TKIP"; + + case IW_AUTH_CIPHER_CCMP: + return "CCMP"; + + case IW_AUTH_CIPHER_AES_CMAC: + return "AES-128-CMAC"; + + default: + nerr("ERROR: Failed to transfer wifi cipher: %d", cipher); + return NULL; + } +} + +static void mac_addr_n2a(char *mac_addr, unsigned char *arg) +{ + int i; + int l; + + for (l = 0, i = 0; i < ETH_ALEN; i++) + { + if (i == 0) + { + sprintf(mac_addr + l, "%02x", arg[i]); + l += 2; + } + else + { + sprintf(mac_addr + l, ":%02x", arg[i]); + l += 3; + } + } +} + +static int mac_addr_a2n(unsigned char *mac_addr, char *arg) +{ + int i; + + for (i = 0; i < ETH_ALEN ; i++) + { + int temp; + char *cp = strchr(arg, ':'); + + if (cp) + { + *cp = 0; + cp++; + } + + if (sscanf(arg, "%x", &temp) != 1) + { + return -EINVAL; + } + + if (temp < 0 || temp > 255) + { + return -EINVAL; + } + + mac_addr[i] = temp; + if (!cp) + { + break; + } + + arg = cp; + } + + if (i < ETH_ALEN - 1) + { + return -EINVAL; + } + + return OK; +} + +static int copy_scan_results(struct sim_scan_result_s *scan_req, + struct sim_bss_info_s *info) +{ + int need_len; + char *pointer; + struct iw_event *iwe; + + need_len = IW_EV_LEN(ap_addr) + IW_EV_LEN(qual) + + IW_EV_LEN(freq) + IW_EV_LEN(data) + IW_EV_LEN(essid); + + if (scan_req->cur_len + need_len > scan_req->total_len) + { + scan_req->cur_len += need_len; + return -E2BIG; + } + + /* Copy scan result */ + + pointer = scan_req->buf + scan_req->cur_len; + + /* 1.Copy BSSID */ + + iwe = (struct iw_event *)pointer; + iwe->cmd = SIOCGIWAP; + iwe->u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(&iwe->u.ap_addr.sa_data, + info->BSSID.ether_addr_octet, IFHWADDRLEN); + iwe->len = IW_EV_LEN(ap_addr); + pointer += iwe->len; + + /* 2.Copy ESSID */ + + iwe = (struct iw_event *)pointer; + iwe->cmd = SIOCGIWESSID; + iwe->u.essid.flags = 0; + iwe->u.essid.length = MIN(info->ssid_len, 32); + iwe->u.essid.pointer = (void *)sizeof(iwe->u.essid); + memcpy(&iwe->u.essid + 1, info->ssid, iwe->u.essid.length); + iwe->len = IW_EV_LEN(essid) + ((iwe->u.essid.length + 3) & ~3); + pointer += iwe->len; + + /* 3.Copy link quality info */ + + iwe = (struct iw_event *)pointer; + iwe->cmd = IWEVQUAL; + iwe->u.qual.qual = info->snr; + iwe->u.qual.level = info->RSSI; + iwe->u.qual.noise = info->phy_noise; + iwe->u.qual.updated = IW_QUAL_DBM | IW_QUAL_ALL_UPDATED; + iwe->len = IW_EV_LEN(qual); + pointer += iwe->len; + + /* 4.Copy AP control channel */ + + iwe = (struct iw_event *)pointer; + iwe->cmd = SIOCGIWFREQ; + iwe->u.freq.e = -1; + iwe->u.freq.m = info->freq * 10; + iwe->len = IW_EV_LEN(freq); + pointer += iwe->len; + + /* 5.Copy AP encryption mode */ + + iwe = (struct iw_event *)pointer; + iwe->cmd = SIOCGIWENCODE; + iwe->u.data.flags = info->capability & IEEE80211_CAP_PRIVACY ? + IW_ENCODE_ENABLED | IW_ENCODE_NOKEY : + IW_ENCODE_DISABLED; + iwe->u.data.length = 0; + iwe->u.essid.pointer = NULL; + iwe->len = IW_EV_LEN(data); + pointer += iwe->len; + + scan_req->cur_len = pointer - scan_req->buf; + + return OK; +} + +static int get_bss_info(struct sim_bss_info_s *bss_info, char *buf, int len) +{ + unsigned char bssid[ETH_ALEN]; + char str[128]; + char *p = NULL; + char *s = NULL; + int i = 0; + + memset(bss_info, 0, sizeof(*bss_info)); + for (i = 0, p = buf; p - buf < len; p++, i++) + { + ninfo(" var_idx%d: ", i); + s = p; + while (*p != '\n' && *p != ' ' && *p != '\0') + { + p++; + } + + memset(str, 0, sizeof(str)); + memcpy(str, s, p - s); + ninfo("%s", str); + + switch (i) + { + case 0: /* bssid */ + mac_addr_a2n(bssid, str); + memcpy(bss_info->BSSID.ether_addr_octet, + bssid, IFHWADDRLEN); + break; + case 1: /* freq */ + bss_info->freq = atoi(str); + break; + case 2: /* signal */ + bss_info->RSSI = atoi(str); + break; + case 3: /* security */ + bss_info->capability |= strlen(str) > strlen("[ESS]") ? + IEEE80211_CAP_PRIVACY : 0x01; + break; + case 4: /* ssid */ + memcpy(bss_info->ssid, str, p - s); + bss_info->ssid_len = p - s; + break; + default: + break; + } + } + + return OK; +} + +static int get_scan_results(struct sim_netdev_s *wifidev, + struct sim_scan_result_s *scan_reqs) +{ + int ret; + int size = 4096; + char *rbuf; + char bss[128]; + char *p; + char *s; + struct sim_bss_info_s bss_info; + + rbuf = malloc(size * sizeof(char)); + if (rbuf == NULL) + { + nerr("malloc failed!\n"); + return -ENOMEM; + } + +get_scan: + ret = host_system(rbuf, size, "%s %s -i%s %s", WPA_CLI, WPA_CTRL_PATH, + wifidev->host_ifname, "scan_results | grep \"\\[ESS\"|" + "awk '{print $1,$2,$3,$4,$5}'"); + if (ret < 0) + { + nerr("get scan failed\n"); + free(rbuf); + return ret; + } + else if (ret == size) + { + size += 1024; + p = realloc(rbuf, size); + if (p == NULL) + { + nerr("get scan faied in realloc!\n"); + free(rbuf); + return -ENOMEM; + } + + rbuf = p; + goto get_scan; + } + + ret = -EAGAIN; + for (p = rbuf; *p != '\0'; p++) + { + s = p; + while (*p != '\n') + { + p++; + } + + memset(bss, 0, sizeof(bss)); + memcpy(bss, s, p - s + 1); + ninfo("%s\n", bss); + + get_bss_info(&bss_info, bss, strlen(bss)); + ninfo("\n"); + + ret = copy_scan_results(scan_reqs, &bss_info); + if (ret < 0) + { + break; + } + } + + free(rbuf); + + return ret; +} + +static bool get_wpa_state(struct sim_netdev_s *wifidev) +{ + int ret; + char rbuf[BUF_LEN]; + + ret = get_cmd(wifidev, rbuf, BUF_LEN, "%s", + "status | grep wpa_state | awk -F'=' '{print $2}'"); + + if (ret > 0 && !strncmp(rbuf, "COMPLETED", strlen("COMPLETED"))) + { + return true; + } + + return false; +} + +static int get_wpa_ssid(struct sim_netdev_s *wifidev, struct iw_point *essid) +{ + int ret; + char rbuf[BUF_LEN]; + + ret = get_cmd(wifidev, rbuf, BUF_LEN, "%s", + "status | grep ^ssid | awk -F'=' '{print $2}'"); + + if (ret > 0 && ret <= essid->length) + { + strlcpy(essid->pointer, rbuf, ret); + essid->length = ret - 1; + } + + return ret; +} + +static int get_wpa_freq(struct sim_netdev_s *wifidev) +{ + return get_cmd_result_num(wifidev, + "status | grep freq | awk -F'=' '{print $2}'"); +} + +static int freq_to_channel(uint16_t freq) +{ + int channel = 0; + + /* If the freq is a valid channel, we think that + * user wants to directly configure the channel. + */ + + if ((freq >= 1 && freq <= 14) || + (freq >= 36 && freq <= 165) || + (freq >= 182 && freq <= 196)) + { + channel = freq; + return channel; + } + + if (freq >= 2412 && freq <= 2484) + { + if (freq == 2484) + { + channel = 14; + } + else + { + channel = freq - 2407; + if (channel % 5) + { + return OK; + } + + channel /= 5; + } + + return channel; + } + + if (freq >= 5005 && freq < 5900) + { + if (freq % 5) + { + return OK; + } + + channel = (freq - 5000) / 5; + return channel; + } + + if (freq >= 4905 && freq < 5000) + { + if (freq % 5) + { + return OK; + } + + channel = (freq - 4000) / 5; + return channel; + } + + return OK; +} + +static int wifidriver_start_scan(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret; + uint8_t mode = wifidev->mode; + + if (mode == IW_MODE_MASTER) + { + return OK; + } + else if (mode == IW_MODE_INFRA) + { + ret = set_cmd(wifidev, "scan"); + if (ret == -EINVAL) + { + nerr("ERROR: scan is running!\n"); + } + } + else + { + nerr("ERROR: Scan do not support the mode %d ! \n", mode); + ret = -ENOSYS; + } + + return ret; +} + +static int wifidriver_scan_result(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + struct sim_scan_result_s scan_req; + int ret = 0; + + if (wifidev->mode == IW_MODE_MASTER) + { + return OK; + } + else if (wifidev->mode == IW_MODE_INFRA) + { + scan_req.buf = pwrq->u.data.pointer; + scan_req.total_len = pwrq->u.data.length; + scan_req.cur_len = 0; + + ret = get_scan_results(wifidev, &scan_req); + + pwrq->u.data.length = scan_req.cur_len; + } + + return ret; +} + +static int wifidriver_set_auth(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret = 0; + int flag = pwrq->u.param.flags & IW_AUTH_INDEX; + int value = pwrq->u.param.value; + + switch (flag) + { + case IW_AUTH_WPA_VERSION: + + /* record the value */ + + wifidev->proto = value >> 1; + + ninfo("proto=%s\n", get_authstr(value)); + + if (wifidev->mode == IW_MODE_INFRA) + { + ret = WPA_SET_NETWORK(wifidev, "proto %s", get_authstr(value)); + } + else if(wifidev->mode == IW_MODE_MASTER) + { + /* set ap value */ + + ret = set_cmd(wifidev, "set wpa %d", wifidev->proto); + if (value == IW_AUTH_WPA_VERSION_WPA || + value == IW_AUTH_WPA_VERSION_WPA2) + { + ret = set_cmd(wifidev, "set wpa_key_mgmt %s", "WPA-PSK"); + } + else + { + ret = set_cmd(wifidev, "set wpa %d", wifidev->proto); + } + } + break; + + case IW_AUTH_CIPHER_PAIRWISE: + + /* record the value */ + + wifidev->pairwise_chiper = value; + + ninfo("pairwise=%s\n", get_cipherstr(value)); + + if (wifidev->mode == IW_MODE_INFRA) + { + ret = WPA_SET_NETWORK(wifidev, "pairwise %s", + get_cipherstr(value)); + } + else if(wifidev->mode == IW_MODE_MASTER) + { + /* set rsn_pairwise value */ + + ret = set_cmd(wifidev, "set rsn_pairwise %s", + get_cipherstr(value)); + } + break; + default: + nerr("ERROR: Unknown cmd %d\n", flag); + return -ENOSYS; + } + + return ret; +} + +static int wifidriver_get_auth(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret = 0; + + switch (wifidev->mode) + { + case IW_MODE_INFRA: + break; + case IW_MODE_MASTER: + break; + default: + break; + } + + return ret; +} + +static int wifidriver_set_psk(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + char psk_buf[64]; + struct iw_encode_ext *ext; + int ret = 0; + + ext = (struct iw_encode_ext *)pwrq->u.encoding.pointer; + + memset(psk_buf, 0, sizeof(psk_buf)); + memcpy(psk_buf, ext->key, ext->key_len); + + ninfo("psk=%s, key_len= %d, alg=%u\n", psk_buf, ext->key_len, ext->alg); + + /* set auth_alg */ + + switch (ext->alg) + { + case IW_ENCODE_ALG_TKIP: + case IW_ENCODE_ALG_CCMP: + break; + case IW_ENCODE_ALG_NONE: + case IW_ENCODE_ALG_WEP: + default: + return -ENOSYS; + } + + switch (wifidev->mode) + { + case IW_MODE_INFRA: + WPA_SET_NETWORK(wifidev, "auth_alg %s", get_auth_algstr(ext->alg)); + WPA_SET_NETWORK(wifidev, "psk \\\"%s\\\"", psk_buf); + WPA_SET_NETWORK(wifidev, "key_mgmt %s", "WPA-PSK WPA-EAP"); + + /* Set the psk flag for security ap. */ + + wifidev->psk_flag = 1; + break; + case IW_MODE_MASTER: + + /* set wpa_passphrase psk_buf */ + + ret = set_cmd(wifidev, "set wpa_passphrase %s", psk_buf); + wifidev->psk_flag = 1; + break; + default: + break; + } + + return ret ; +} + +static int wifidriver_set_essid(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + char ssid_buf[SSID_MAX_LEN]; + int ret = 0; + uint8_t ssid_len = pwrq->u.essid.length; + + memset(ssid_buf, 0, sizeof(ssid_buf)); + memcpy(ssid_buf, pwrq->u.essid.pointer, pwrq->u.essid.length); + ninfo("ssid=%s, ssid_len=%d\n", ssid_buf, ssid_len); + + memset(wifidev->ssid, 0, SSID_MAX_LEN); + memcpy(wifidev->ssid, ssid_buf, ssid_len); + + if (wifidev->mode == IW_MODE_INFRA) + { + WPA_SET_NETWORK(wifidev, "ssid \\\"%s\\\"", ssid_buf); + + if (wifidev->psk_flag == 0) + { + /* should set the key_mgmt for open */ + + WPA_SET_NETWORK(wifidev, "key_mgmt %s", "NONE"); + wifidev->key_mgmt = 0; + } + + ret = set_cmd(wifidev, "save_config"); + } + else if (wifidev->mode == IW_MODE_MASTER) + { + /* set ssid ssid_buf */ + + ret = set_cmd(wifidev, "set ssid %s", ssid_buf); + if (wifidev->psk_flag == 0) + { + /* should set the key_mgmt for open */ + + ret = set_cmd(wifidev, "set wpa %d", 0); + wifidev->proto = 0; + } + + ret = set_cmd(wifidev, "reload"); + } + + return ret; +} + +static int wifidriver_get_essid(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret = 0; + struct iw_point *essid = &pwrq->u.essid; + + switch (wifidev->mode) + { + case IW_MODE_INFRA: + { + /* get essid */ + + get_wpa_ssid(wifidev, essid); + + /* get wpa_state */ + + if (get_wpa_state(wifidev)) + { + essid->flags = IW_ESSID_ON; + } + else + { + essid->flags = IW_ESSID_OFF; + } + } + break; + case IW_MODE_MASTER: + break; + default: + break; + } + + return ret; +} + +static int wifidriver_set_bssid(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret = 0; + struct sockaddr *sockaddr = &pwrq->u.ap_addr; + unsigned char *pdata = (unsigned char *)sockaddr->sa_data; + char bssid_buf[20]; + + memset(bssid_buf, 0, sizeof(bssid_buf)); + mac_addr_n2a(bssid_buf, pdata); + + ninfo("bssid=%s \n", bssid_buf); + + memset(wifidev->bssid, 0, 6); + memcpy(wifidev->bssid, pdata, 6); + + if (wifidev->mode == IW_MODE_INFRA) + { + WPA_SET_NETWORK(wifidev, "bssid %s", bssid_buf); + + if (wifidev->psk_flag == 0) + { + /* should set the key_mgmt for open */ + + WPA_SET_NETWORK(wifidev, "key_mgmt %s", "NONE"); + wifidev->key_mgmt = 0; + } + + set_cmd(wifidev, "save_config"); + } + else if (wifidev->mode == IW_MODE_MASTER) + { + ret = -ENOSYS; + } + + return ret; +} + +static int wifidriver_start_connect(struct sim_netdev_s *wifidev) +{ + switch (wifidev->mode) + { + case IW_MODE_INFRA: + + /* If wlan is connected, should be disconnect before connectting. */ + + set_cmd(wifidev, "select_network %d", wifidev->network_id); + set_cmd(wifidev, "disconnect"); + set_cmd(wifidev, "reconnect"); + + /* Enshure that the default is non-encrypted. */ + + if (wifidev->psk_flag) + { + wifidev->psk_flag = 0; + } + break; + case IW_MODE_MASTER: + + set_cmd(wifidev, "disable"); + set_cmd(wifidev, "enable"); + + if (wifidev->psk_flag) + { + wifidev->psk_flag = 0; + } + break; + default: + break; + } + + return OK; +} + +static int wifidriver_start_disconnect(struct sim_netdev_s *wifidev) +{ + int ret; + + switch (wifidev->mode) + { + case IW_MODE_INFRA: + ret = set_cmd(wifidev, "disconnect"); + break; + case IW_MODE_MASTER: + ret = set_cmd(wifidev, "disable"); + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +static int wifidriver_get_mode(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + pwrq->u.mode = wifidev->mode; + return OK; +} + +static int wifidriver_set_mode(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int ret; + + /* IW_MODE_INFRA indicates station */ + + wifidev->mode = pwrq->u.mode; + switch (wifidev->mode) + { + case IW_MODE_INFRA: + + /* Start the sta config, including wpa_supplicant and udhcpc. */ + + ret = host_system(NULL, 0, + "/usr/bin/sudo %s/"SIMWIFI_FILE" start_sta %s", + TOPDIR, wifidev->host_ifname); + if (ret == 0) + { + /* Check the network number, if no network, should add new network. + * Then, set the new network id to network_id. + */ + + int num; + int network_id = 0; + + num = wpa_get_network_num(wifidev); + if (num < 1) + { + network_id = wpa_add_network(wifidev); + } + else + { + network_id = wpa_get_last_network_id(wifidev, num); + } + + wifidev->network_id = network_id; + } + break; + case IW_MODE_MASTER: + + /* Start the hostapd. */ + + ret = host_system(NULL, 0, + "/usr/bin/sudo %s/"SIMWIFI_FILE" start_ap %s", + TOPDIR, wifidev->host_ifname); + + break; + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static int wifidriver_set_country(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + char country[4] = + { + 0 + }; + + if (wifidev->mode != IW_MODE_INFRA) + { + return OK; + } + + memcpy(country, pwrq->u.data.pointer, pwrq->u.data.length); + + ninfo("set country is %s\n", country); + + return set_cmd(wifidev, "set country %s", country); +} + +static int wifidriver_get_country(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + char country[128]; + int ret; + + if (wifidev->mode != IW_MODE_INFRA) + { + return OK; + } + + memset(country, 0, sizeof(country)); + + ret = host_system(country, sizeof(country), + "%s %s -i%s %s", WPA_CLI, WPA_CTRL_PATH, + wifidev->host_ifname, "get country"); + + if (ret <= 0) + { + nerr("get country NULL."); + return -ENODATA; + } + + if (strncmp(country, "FAIL", 4)) + { + memcpy(pwrq->u.data.pointer, country, 2); + ((uint8_t *)pwrq->u.data.pointer)[2] = '\0'; + ret = 0; + } + else + { + nerr("get country FAILED."); + ret = -ENODATA; + } + + return ret; +} + +int wifidriver_set_freq(struct sim_netdev_s *wifidev, struct iwreq *pwrq) +{ + int channel; + int ret = 0; + + switch (wifidev->mode) + { + case IW_MODE_INFRA: + break; + case IW_MODE_MASTER: + channel = freq_to_channel(pwrq->u.freq.m); + if (channel > 0) + { + ret = set_cmd(wifidev, "set channel %d", channel); + ret = set_cmd(wifidev, "disable"); + ret = set_cmd(wifidev, "enable"); + } + break; + default: + break; + } + + return ret; +} + +static int wifidriver_get_freq(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + switch (wifidev->mode) + { + case IW_MODE_INFRA: + if (get_wpa_state(wifidev)) + { + pwrq->u.freq.flags = IW_FREQ_FIXED; + pwrq->u.freq.e = 0; + pwrq->u.freq.m = get_wpa_freq(wifidev); + } + else + { + pwrq->u.freq.flags = IW_FREQ_AUTO; + pwrq->u.freq.e = 0; + pwrq->u.freq.m = 2412; + } + break; + case IW_MODE_MASTER: + break; + default: + break; + } + + return OK; +} + +static int wifidriver_get_range(struct sim_netdev_s *wifidev, + struct iwreq *pwrq) +{ + int k; + struct iw_range *range = (struct iw_range *)pwrq->u.data.pointer; + + /* default in china. */ + + range->num_frequency = 13; + for (k = 1; k <= range->num_frequency; k++) + { + range->freq[k - 1].i = k; + range->freq[k - 1].e = 0; + range->freq[k - 1].m = 2407 + 5 * k; + } + + return OK; +} + +static int wifidriver_connect(struct netdev_lowerhalf_s *dev) +{ + int ret; + + ret = wifidriver_start_connect((struct sim_netdev_s *)dev); + if (ret >= 0) + { + ret = netdev_lower_carrier_on(dev); + } + + return ret; +} + +static int wifidriver_disconnect(struct netdev_lowerhalf_s *dev) +{ + int ret; + + ret = wifidriver_start_disconnect((struct sim_netdev_s *)dev); + if (ret >= 0) + { + ret = netdev_lower_carrier_off(dev); + } + + return ret; +} + +static int wifidriver_essid(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_set_essid(wifidev, iwr); + } + else + { + return wifidriver_get_essid(wifidev, iwr); + } +} + +static int wifidriver_bssid(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + int ret; + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + ret = wifidriver_set_bssid(wifidev, iwr); + if (ret >= 0) + { + ret = wifidriver_start_connect(wifidev); + } + } + else + { + return -ENOTTY; + } + + return ret; +} + +static int wifidriver_passwd(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + if (set) + { + return wifidriver_set_psk((struct sim_netdev_s *)dev, iwr); + } + else + { + return -ENOTTY; + } +} + +static int wifidriver_mode(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_set_mode(wifidev, iwr); + } + else + { + return wifidriver_get_mode(wifidev, iwr); + } +} + +static int wifidriver_auth(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_set_auth(wifidev, iwr); + } + else + { + return wifidriver_get_auth(wifidev, iwr); + } +} + +static int wifidriver_freq(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_set_freq(wifidev, iwr); + } + else + { + return wifidriver_get_freq(wifidev, iwr); + } +} + +static int wifidriver_bitrate(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + return -ENOTTY; +} + +static int wifidriver_txpower(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + return -ENOTTY; +} + +static int wifidriver_country(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_set_country(wifidev, iwr); + } + else + { + return wifidriver_get_country(wifidev, iwr); + } +} + +static int wifidriver_sensitivity(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + return -ENOTTY; +} + +static int wifidriver_scan(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr, bool set) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (set) + { + return wifidriver_start_scan(wifidev, iwr); + } + else + { + return wifidriver_scan_result(wifidev, iwr); + } +} + +static int wifidriver_range(struct netdev_lowerhalf_s *dev, + struct iwreq *iwr) +{ + return wifidriver_get_range((struct sim_netdev_s *)dev, iwr); +} + +static bool wifidriver_connected(struct netdev_lowerhalf_s *dev) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + if (wifidev->mode == IW_MODE_MASTER) + { + return true; + } + else if (wifidev->mode == IW_MODE_INFRA) + { + return get_wpa_state(wifidev); + } + + return false; +} + +static void wifidriver_init(struct netdev_lowerhalf_s *dev, int devidx) +{ + struct sim_netdev_s *wifidev = (struct sim_netdev_s *)dev; + + wifidev->mode = IW_MODE_AUTO; + wifidev->devidx = devidx; + + /* The default host wlan interface name is corresponding to the nuttx + * wlan interface name. If not, should modify the host wlan interface + * name. + */ + + snprintf(wifidev->host_ifname, IFNAMSIZ, "wlan%d", devidx); + + /* Bind the wireless ops interfaces. */ + + dev->iw_ops = &g_iw_ops; +} diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5028e0db17..d394c44eb0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -48,7 +48,7 @@ config NETDEV_WORK_THREAD_PRIORITY config NETDEV_WIRELESS_HANDLER bool "Support wireless handler in upper-half driver" default y - depends on NETDEV_IOCTL + depends on NETDEV_WIRELESS_IOCTL ---help--- Enable the wireless handler support in upper-half driver. diff --git a/tools/simwifi/README b/tools/simwifi/README new file mode 100644 index 0000000000..a29cddc2a1 --- /dev/null +++ b/tools/simwifi/README @@ -0,0 +1,115 @@ + +# Function + +The simwifi can provides host Settings for sim wifi on nuttx sim emulator. +The script sim_wifi.sh supports two modes that simulate wifi, HWSIM and RNC +(real network card). + + - In the HWSIM mode, we simulates two wlan interfaces. The wlan0 is STA and + the wlan1 is AP. The wlan0 can connect to the wlan1 in the nuttx simulator. + - In the RNC mode, we can use the same wlan interface name on the nuttx simulator + to control the connection behavior of the real wireless card. + +# Config + +Before using the Sim WiFi function, we need to perform the following +configurations: + + - nuttx + SIM_NETDEV_NUMBER=3 + SIM_WIFIDEV_NUMBER=2 + SIM_NETDEV_TAP=y + DRIVERS_IEEE80211=y + NETDEV_WIRELESS_HANDLER=y + + - apps + WIRELESS_WAPI_CMDTOOL=y + SYSTEM_DHCPC_RENEW=y + NETUTILS_DHCPD=y + +# Using + +We can use the './tools/simwifi/sim_wifi.sh help' command to view the commands +provided by the sim_wifi.sh script and the results are as follows. + +sim_wifi.sh (rename | + init |clean | + start_wpa |stop_wpa | + start_hostapd |stop_hostapd | + start_udhcpc |stop_udhcpc | + start_dhcp |stop_dhcp | + start_hwsim |stop_hwsim |up_hwsim | + start_net |stop_net | + start_sta |stop_sta | + start_ap [eth0] |stop_ap [eth0] | + start_bridge |stop_bridge | + show | help) + + - Init the simwifi, the command format is as follows: + sudo ./tools/simwifi/sim_wifi.sh init + + The is the name of the interface for accessing the Internet. + The is the simwifi mode, HWSIM and RNC. + + Setting HWSIM: + sudo ./tools/simwifi/sim_wifi.sh init eno1 HWSIM + + Setting RNC: + sudo ./tools/simwifi/sim_wifi.sh init eno1 RNC + + - In HWSIM mode: + Start the hwsim services, the command is as follows. + sudo ./tools/simwifi/sim_wifi.sh start_hwsim + + Stop the hwsim services, the command is as follows + sudo ./tools/simwifi/sim_wifi.sh stop_hwsim + + + - In RNC mode: + Maybe the real wireless card name format is not wlanx, in this case + we need to change it to wlanx format. The command is as follows + sudo simwifi rename wlanx + + * Set the real wireless network card to STA mode. + sudo ./tools/simwifi/sim_wifi.sh start_sta wlan0 + + * Set the real wireless network card to AP mode. + sudo ./tools/simwifi/sim_wifi.sh start_ap wlan0 + +Finally we can clean up all the files, configurations and services of the simwifi. + sudo ./tools/simwifi/sim_wifi.sh clean + +# Location problems + We can use the following command to locate the problem and display the + status. + cmd: sudo ./tools/simwifi/sim_wifi.sh show + log: + +/var/run/simwifi +dnsmasq.conf hostapd simwifi.log udhcpc.script wpa_supplicant.pid +dnsmasq.leases hostapd.conf simwifi.state wpa_supplicant +dnsmasq.pid simwifi.conf udhcpc.pid wpa_supplicant.conf + +services list +root 1880671 2046 0 10月10 ? 00:00:00 /usr/sbin/wpa_supplicant -B -c /var/run/simwifi/wpa_supplicant.conf -iwlan0 -P /var/run/simwifi/wpa_supplicant.pid +nobody 1880680 2046 0 10月10 ? 00:00:00 /usr/sbin/dnsmasq -inuttx0 -C /var/run/simwifi/dnsmasq.conf --log-debug -x /var/run/simwifi/dnsmasq.pid +root 1880672 2046 0 10月10 ? 00:00:00 /usr/sbin/udhcpc -i wlan0 -p /var/run/simwifi/udhcpc.pid -s /var/run/simwifi/udhcpc.script + +bridge nuttx0 +222: tap0: mtu 1500 qdisc fq_codel master nuttx0 state UNKNOWN mode DEFAULT group default qlen 1000 + link/ether 2e:b0:bc:79:41:02 brd ff:ff:ff:ff:ff:ff +223: tap1: mtu 1500 qdisc noop master nuttx0 state DOWN mode DEFAULT group default qlen 1000 + link/ether a6:33:96:26:a4:1d brd ff:ff:ff:ff:ff:ff + +default config +defwan:eno1 +mode:rnc + +state:SW_STA +wlan:wlan0 +br:nuttx0 + +default via 10.221.127.254 dev eno1 proto dhcp metric 100 +10.0.1.0/24 dev nuttx0 proto kernel scope link src 10.0.1.1 +10.221.96.0/19 dev eno1 proto kernel scope link src 10.221.108.5 metric 100 + diff --git a/tools/simwifi/dnsmasq.conf b/tools/simwifi/dnsmasq.conf new file mode 100644 index 0000000000..b78c947feb --- /dev/null +++ b/tools/simwifi/dnsmasq.conf @@ -0,0 +1,8 @@ +dhcp-leasefile=/var/run/simwifi/dnsmasq.leases +port=0 + +dhcp-range=10.0.1.100,10.0.1.250,255.255.255.0,12h +dhcp-option=option:router,10.0.1.1 +dhcp-option=option:dns-server,8.8.8.8,8.8.4.4 +dhcp-option=option:netmask,255.255.255.0 + diff --git a/tools/simwifi/hostapd.conf b/tools/simwifi/hostapd.conf new file mode 100644 index 0000000000..9399a248c7 --- /dev/null +++ b/tools/simwifi/hostapd.conf @@ -0,0 +1,14 @@ +ctrl_interface=/var/run/simwifi/hostapd +driver=nl80211 +ssid=NuttX_WiFi +hw_mode=g +channel=8 +wmm_enabled=0 +macaddr_acl=0 +auth_algs=1 +ignore_broadcast_ssid=0 +wpa=2 +wpa_passphrase=12345678 +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP +rsn_pairwise=CCMP diff --git a/tools/simwifi/hostapd_hwsim.conf b/tools/simwifi/hostapd_hwsim.conf new file mode 100644 index 0000000000..e17351d84c --- /dev/null +++ b/tools/simwifi/hostapd_hwsim.conf @@ -0,0 +1,14 @@ +ctrl_interface=/var/run/simwifi/hostapd +driver=nl80211 +ssid=Hwsim_WiFi +hw_mode=g +channel=8 +wmm_enabled=0 +macaddr_acl=0 +auth_algs=1 +ignore_broadcast_ssid=0 +wpa=2 +wpa_passphrase=12345678 +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP +rsn_pairwise=CCMP diff --git a/tools/simwifi/sim_wifi.sh b/tools/simwifi/sim_wifi.sh new file mode 100755 index 0000000000..6858b158f7 --- /dev/null +++ b/tools/simwifi/sim_wifi.sh @@ -0,0 +1,576 @@ +#!/bin/bash + +#**************************************************************************** +# tools/simwifi/sim_wifi.sh +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +#**************************************************************************** +# + +NUTTX_BR_IF="nuttx0" +RUN_DIR="/var/run/simwifi" +CUR_DIR="" +DBG_LEVEL=1 + +WPA_PID_FILE="$RUN_DIR/wpa_supplicant.pid" +WPA_CONF_FILE="$RUN_DIR/wpa_supplicant.conf" +HOSTAPD_PID_FILE="$RUN_DIR/hostapd.pid" +HOSTAPD_CONF_FILE="$RUN_DIR/hostapd.conf" +DNSMASQ_PID="$RUN_DIR/dnsmasq.pid" +DNSMASQ_CONF="$RUN_DIR/dnsmasq.conf" +UDHCPC_PID="$RUN_DIR/udhcpc.pid" +UDHCPC_SCRIPT="$RUN_DIR/udhcpc.script" + +LOG_FILE="$RUN_DIR/simwifi.log" +STATE_FILE="$RUN_DIR/simwifi.state" +DEFCONF_FILE="$RUN_DIR/simwifi.conf" + +DHCP_CLIENT=$(which udhcpc) +DNSMASQ=$(which dnsmasq) +WPA_SUPPLICANT=$(which wpa_supplicant) +HOSTAPD=$(which hostapd) + +# print the debug message +sw_dbg() +{ + [ $1 -ge $DBG_LEVEL ] && { + echo "$2" + } +} + +# get var from the file +# $1:key $2:file +get_var() +{ + cat $2 | grep $1 | awk -F':' '{print $2}' +} + +check_state() +{ + old_state=$(get_var state $STATE_FILE) + sw_dbg 1 "new state:$1, old_state:$old_state" + + if [ "$1" = "$old_state" ]; then + sw_dbg 1 "cur_state is $1" + exit 0 + fi +} + +# set simwifi state +set_state() +{ + state=$1 + wlan_if=$2 + br_if=$3 + wan_if=$4 + sw_dbg 1 "[set_state] new state:$1" + + if [ "$state" != "SW_INIT" -a "$state" != "SW_HWSIM" -a \ + "$state" != "SW_NET" -a "$state" != "SW_STA" -a \ + "$state" != "SW_AP" -a "$state" != "SW_STAAP" ]; then + echo "no state: $1" + exit -1 + fi + + sw_dbg 1 "state:$state wlan_if:$wlan_if, br_if:$br_if wan_if:$wan_if" + + echo "state:$state" > $STATE_FILE + [ -n "$wlan_if" ] && echo "wlan:$wlan_if" >> $STATE_FILE + [ -n "$br_if" ] && echo "br:$br_if" >> $STATE_FILE + [ -n "$wan_if" ] && echo "wan:$wan_if" >> $STATE_FILE +} + +# recover the simwifi state to SW_INIT + +recovery_to_init() +{ + cur_state=$(get_var state $STATE_FILE) + wlan_if=$(get_var wlan $STATE_FILE) + br_if=$(get_var br $STATE_FILE) + + sw_dbg 1 "[recovery_to_init] cur_s:$cur_state" + case $cur_state in + SW_INIT) ;; + SW_HWSIM) stop_hwsim;; + SW_STAAP) stop_staap;; + SW_NET) stop_net $wlan_if;; + SW_STA) stop_sta;; + SW_AP) stop_ap $wlan_if;; + *) set_state SW_INIT;; + esac +} + +# Get the absolute pathname of sim_wifi.sh + +get_script_path() +{ + SOURCE=$1 + + while [ -h "$SOURCE" ]; do + SOURCE=$(readlink $SOURCE) + done + + CUR_DIR=$(cd $(dirname $SOURCE) && pwd) +} + +# Copy the configure file to the $RUN_DIR + +init_env() +{ + sw_dbg 1 "init env" + + [ -f "$STATE_FILE" ] && { + check_hwsim_mode + recovery_to_init + } + + mkdir -p $RUN_DIR + touch $STATE_FILE + + if [ "$1" = "hwsim" ]; then + cp -fr $CUR_DIR/hostapd_hwsim.conf $HOSTAPD_CONF_FILE + cp -fr $CUR_DIR/wpa_supplicant_hwsim.conf $WPA_CONF_FILE + else + cp -fr $CUR_DIR/hostapd.conf $HOSTAPD_CONF_FILE + cp -fr $CUR_DIR/wpa_supplicant.conf $WPA_CONF_FILE + fi + + cp -fr $CUR_DIR/dnsmasq.conf $DNSMASQ_CONF + cp -fr $CUR_DIR/udhcpc.script $UDHCPC_SCRIPT +} + +# Rename the interface name + +rename_ifdev() +{ + old_name=$1 + new_name=$2 + + ifconfig $old_name down && ip link set $old_name name $new_name + ifconfig $new_name up +} + +kill_service() +{ + service_name=$(basename $1 .pid) + sw_dbg 1 "kill $service_name" + if [ -f "$1" ]; then + pid=$(cat $1) + kill -9 $pid + rm $1 + else + sw_dbg 1 "$1 isn't existed." + killall $service_name + fi +} + +stop_wpa() +{ + kill_service $WPA_PID_FILE +} + +stop_hostapd() +{ + kill_service $HOSTAPD_PID_FILE +} + +start_hostapd() +{ + sw_dbg 1 "start ap on $1" + + #Waiting 1s. If not, the hostapd starting maybe fail on switching mode. + + sleep 1 + $HOSTAPD -B -i$1 -P $HOSTAPD_PID_FILE $HOSTAPD_CONF_FILE -t &>>$LOG_FILE +} + +start_wpa() +{ + sw_dbg 1 "start sta on $1" + + #Waiting 1s. If not, the wap_supplicant starting maybe fail on switching mode. + + sleep 1 + $WPA_SUPPLICANT -B -c $WPA_CONF_FILE -i$1 -P $WPA_PID_FILE &>>$LOG_FILE +} + +start_udhcpc() +{ + sw_dbg 1 "start dhcp client on $1" + + [ -n "$2" ] && script_opt=" -s $UDHCPC_SCRIPT" + + $DHCP_CLIENT -i $1 -p $UDHCPC_PID $script_opt &>>$LOG_FILE & +} + +stop_udhcpc() +{ + kill_service $UDHCPC_PID +} + +start_bridge() +{ + sw_dbg 1 "start bridge to $1" + $CUR_DIR/../simhostroute.sh $1 on &>>$LOG_FILE +} + +stop_bridge() +{ + sw_dbg 1 "stop bridge to $1" + sw_dbg 1 "Warning: The $NUTTX_BR_IF will be deleted!" + $CUR_DIR/../simhostroute.sh $1 off &>>$LOG_FILE +} + +start_dhcp_server() +{ + sw_dbg 1 "start dhcp server on $1" + dbg_option=$($DNSMASQ --help|grep log-debug | awk '{print $1}') + + $DNSMASQ -i$1 -C $DNSMASQ_CONF $dbg_option -x $DNSMASQ_PID &>>$LOG_FILE +} + +stop_dhcp_server() +{ + kill_service $DNSMASQ_PID +} + +check_hwsim_mode() +{ + cur_state=$(get_var state $STATE_FILE) + + sw_dbg 1 "[check_hwsim_mode]state: $cur_state" + if [ "$cur_state" = "SW_HWSIM" ]; then + sw_dbg 1 "cur_state is hwsim mode. \ + Don't set the sta/ap mode." + exit 0 + fi +} + +start_hwsim() +{ + sta_if=${1:-wlan0} + ap_if=${2:-wlan1} + + sw_dbg 1 "start hwsim on $sta_if $ap_if" + + init_env hwsim + start_hostapd $ap_if + start_wpa $sta_if + start_dhcp_server $NUTTX_BR_IF + + set_state SW_HWSIM +} + +stop_hwsim() +{ + stop_wpa + stop_hostapd + + stop_dhcp_server + + set_state SW_INIT +} + +start_net() +{ + init_env + start_wpa $1 + start_udhcpc $1 + start_bridge $1 + start_dhcp_server $NUTTX_BR_IF + + set_state SW_NET $1 $NUTTX_BR_IF $1 +} + +# Warning:The function will delete nuttx0 + +stop_net() +{ + stop_wpa + stop_udhcpc + stop_bridge $1 + stop_dhcp_server + + set_state SW_INIT +} + +start_sta() +{ + [ -z "$(ifconfig | grep "$NUTTX_BR_IF")" ] && { + sw_dbg 1 "Please ensure that the $NUTTX_BR_IF is existed." + exit -2 + } + + check_state SW_STA + check_state SW_STAAP + + init_env + start_wpa $1 + start_udhcpc $1 s + start_dhcp_server $NUTTX_BR_IF + + set_state SW_STA $1 $NUTTX_BR_IF; + + exit 0 +} + +del_gw_wlan() +{ + wlan_if=$1 + router=$(ip route show | grep default | grep $wlan_if) + + [ -n "$router" ] && { + ip route del $router + sw_dbg 1 "del the default router on $wlan_if" + } +} + +stop_sta() +{ + stop_wpa + stop_udhcpc + stop_dhcp_server + + #check and delete default on wlan0 + + wlan_if=$(get_var wlan $STATE_FILE) + del_gw_wlan $wlan_if + + set_state SW_INIT +} + +start_ap() +{ + [ -z "$1" ] && { + echo "Missing parameter wlan interface." + exit -1 + } + + [ -z "$2" ] && { + [ -z "$(ifconfig | grep "$NUTTX_BR_IF")" ] && { + echo "Missing parameter wan interface." + echo "Please ensure that the $NUTTX_BR_IF is existed." + exit -2 + } + + wan_if="" + } || { + wan_if=$2 + } + + check_state SW_AP + check_state SW_STAAP + + init_env + start_hostapd $1 + + # nuttx0 doesn't exist and wan_if is configured. + + [ -z "$(ifconfig | grep "$NUTTX_BR_IF")" -a -n "$wan_if" ] && { + start_bridge $wan_if + } + + ip link set dev $1 master $NUTTX_BR_IF + start_dhcp_server $NUTTX_BR_IF + + set_state SW_AP $1 $wan_if; + + exit 0 +} + +stop_ap() +{ + stop_hostapd + [ -z "$2" ] || stop_bridge $2 + + sw_dbg 1 "stop_ap $1" + ip link set dev $1 nomaster + stop_dhcp_server + + set_state SW_INIT +} + +check_ifname() +{ + [ -z "$(ifconfig | grep "$1")" ] && { + echo "The $1 does not exist." + exit -1 + } +} + +start_staap() +{ + sta_if=${1:-wlan0} + ap_if=${2:-wlan1} + sw_dbg 1 "start staap $sta_if $ap_if" + + for i in $sta_if $ap_if $NUTTX_BR_IF; do + check_ifname $i + done + + check_state SW_STAAP + + init_env + start_hostapd $ap_if + + sleep 1 + start_wpa $sta_if + + ip link set dev $ap_if master $NUTTX_BR_IF + + start_udhcpc $sta_if + start_dhcp_server $NUTTX_BR_IF + + set_state SW_STAAP "$sta_if,$ap_if" $NUTTX_BR_IF +} + +stop_staap() +{ + stop_wpa + stop_hostapd + + stop_udhcpc + stop_dhcp_server + ip link set dev wlan1 nomaster + + set_state SW_INIT +} + +show_process() +{ + ps -ef | grep "$1 " | grep -v grep +} + +show_status() +{ + #1.env conf + [ -d "$RUN_DIR" ] && { + echo "$RUN_DIR" + ls $RUN_DIR + } + + #2. key services + echo -e "\nservices list" + for i in wpa_supplicant hostapd dnsmasq udhcpc; do + show_process $i + done + + #3. bridge nuttx0 info + [ -n "$(ifconfig | grep $NUTTX_BR_IF)" ] && { + echo -e "\nbridge $NUTTX_BR_IF" + ip link show master $NUTTX_BR_IF + } + + #4.show DEFCONF_FILE + echo -e "\ndefault config" + cat $DEFCONF_FILE + + #5. show state + echo "" + cat $STATE_FILE + + #6. show router + echo "" + ip route show + +} + +# $1 is the default wan interface for start_sta +# $2 is the simwifi mode, (rnc/hwsim) + +init() +{ + [ -z "$1" ] && { + echo "Missing the default wan interface." + exit -1 + } + + [ -z "$2" ] && { + echo "Missing the simwifi mode." + exit -2 + } + + init_env + + echo "defwan:$1" > $DEFCONF_FILE + [ -n "$1" -a -n "$(ifconfig | grep $1)" ] && start_bridge $1 + + echo "mode:$2" >> $DEFCONF_FILE + [ "$2" = "hwsim" ] && modprobe mac80211_hwsim + + set_state SW_INIT +} + +clean() +{ + recovery_to_init + + cur_mode=$(get_var mode $DEFCONF_FILE) + [ "$cur_mode" = "hwsim" ] && modprobe -r mac80211_hwsim + + rm -fr $RUN_DIR +} + +usage() +{ + echo "$(basename $SOURCE) (rename |" + echo -e "\t init |clean |" + echo -e "\t start_wpa |stop_wpa |" + echo -e "\t start_hostapd |stop_hostapd |" + echo -e "\t start_udhcpc |stop_udhcpc |" + echo -e "\t start_dhcp |stop_dhcp |" + echo -e "\t start_hwsim |stop_hwsim |up_hwsim |" + echo -e "\t start_staap |stop_staap |" + echo -e "\t start_net |stop_net |" + echo -e "\t start_sta |stop_sta |" + echo -e "\t start_ap [eth0] |stop_ap [eth0] |" + echo -e "\t start_bridge |stop_bridge |" + echo -e "\t show | help)" +} + +# locate the directory of the sim_wifi.sh. + +get_script_path $0 + +case $1 in + init) init $2 $3;; + clean) clean;; + start_bridge) start_bridge $2;; + stop_bridge) stop_bridge $2;; + start_hwsim) start_hwsim $2 $3;; + stop_hwsim) stop_hwsim;; + up_hwsim) ifconfig hwsim0 up;; + start_wpa) start_wpa $2;; + stop_wpa) stop_wpa;; + start_hostapd) start_hostapd $2;; + stop_hostapd) stop_hostapd;; + rename) rename_ifdev $2 $3;; + start_udhcpc) start_udhcpc $2;; + stop_udhcpc) stop_udhcpc;; + start_dhcp) start_dhcp_server $2;; + stop_dhcp) stop_dhcp_server;; + start_net) start_net $2;; + stop_net) stop_net $2;; + start_sta) start_sta $2;; + stop_sta) stop_sta;; + start_ap) start_ap $2 $3;; + stop_ap) stop_ap $2 $3;; + start_staap) start_staap;; + stop_staap) stop_staap;; + show) show_status;; + help|*) usage;; +esac diff --git a/tools/simwifi/udhcpc.script b/tools/simwifi/udhcpc.script new file mode 100644 index 0000000000..06343e06e4 --- /dev/null +++ b/tools/simwifi/udhcpc.script @@ -0,0 +1,40 @@ +#!/bin/sh +# Busybox udhcpc dispatcher script. +# Copyright (C) 2009 by Axel Beckert. +# Copyright (C) 2014 by Michael Tokarev. +# +# Based on the busybox example scripts and the old udhcp source +# Modified base on default.scripts. + +log() { + logger -t "udhcpc[$PPID]" -p daemon.$1 "$interface: $2" +} + +case $1 in + bound|renew) + + # Configure new IP address. + # Do it unconditionally even if the address hasn't changed, + # to also set subnet, broadcast, mtu, ... + busybox ifconfig $interface ${mtu:+mtu $mtu} \ + $ip netmask $subnet ${broadcast:+broadcast $broadcast} + + log info "$1: IP=$ip/$subnet router=$router domain=\"$domain\" dns=\"$dns\" lease=$lease" + ;; + + deconfig) + busybox ip link set $interface up + busybox ip -4 addr flush dev $interface + busybox ip -4 route flush dev $interface + log notice "deconfigured" + ;; + + leasefail | nak) + log err "configuration failed: $1: $message" + ;; + + *) + echo "$0: Unknown udhcpc command: $1" >&2 + exit 1 + ;; +esac diff --git a/tools/simwifi/wpa_supplicant.conf b/tools/simwifi/wpa_supplicant.conf new file mode 100644 index 0000000000..eb9c3877b2 --- /dev/null +++ b/tools/simwifi/wpa_supplicant.conf @@ -0,0 +1,2 @@ +ctrl_interface=/var/run/simwifi/wpa_supplicant +update_config=1 diff --git a/tools/simwifi/wpa_supplicant_hwsim.conf b/tools/simwifi/wpa_supplicant_hwsim.conf new file mode 100644 index 0000000000..6eb22eb087 --- /dev/null +++ b/tools/simwifi/wpa_supplicant_hwsim.conf @@ -0,0 +1,10 @@ +ctrl_interface=/var/run/simwifi/wpa_supplicant +update_config=1 + +network={ + ssid="Hwsim_WiFi" + psk="12345678" + key_mgmt=WPA-PSK + group=CCMP + disabled=1 +}