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 +}