You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/12/15 04:22:17 UTC
(nuttx) branch master updated: qemu/wifi: Add the virtual wifi function on the emulator.
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6a8c638d57 qemu/wifi: Add the virtual wifi function on the emulator.
6a8c638d57 is described below
commit 6a8c638d5714d46e526a5f0a803bb680dfc8e1c4
Author: liqinhui <li...@xiaomi.com>
AuthorDate: Mon Oct 23 14:06:12 2023 +0800
qemu/wifi: Add the virtual wifi function on the emulator.
-The qemu wifi fucntion only supports the STA mode and the following
operations:
wapi mode wlan0 2
wapi scan wlan0
wapi psk wlan0 password 3
wapi essid wlan0 wifi_name 1
wapi show wlan0
wapi disconnect wlan0
-Eanble the virtual wifi function with the MACRO `CONFIG_DRIVERS_WIFI_SIM`.
Signed-off-by: liqinhui <li...@xiaomi.com>
---
drivers/net/CMakeLists.txt | 4 +
drivers/net/Kconfig | 14 +
drivers/net/Make.defs | 4 +
drivers/net/wifi_sim.c | 1946 ++++++++++++++++++++++++++++++++++++++++++
drivers/virtio/virtio-net.c | 71 +-
include/nuttx/net/wifi_sim.h | 72 ++
6 files changed, 2100 insertions(+), 11 deletions(-)
diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt
index 9d5492d249..a04cdf752c 100644
--- a/drivers/net/CMakeLists.txt
+++ b/drivers/net/CMakeLists.txt
@@ -83,5 +83,9 @@ if(CONFIG_NET)
list(APPEND SRCS phy_notify.c)
endif()
+ if(CONFIG_DRIVERS_WIFI_SIM)
+ list(APPEND SRCS wifi_sim.c)
+ endif()
+
target_sources(drivers PRIVATE ${SRCS})
endif()
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c34bc9263a..50f041b983 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -657,4 +657,18 @@ config NETDEV_PHY_DEBUG
endif # ARCH_HAVE_PHY
+config DRIVERS_WIFI_SIM
+ bool "WiFi SIM support"
+ depends on NETDEV_WIRELESS_IOCTL
+ default n
+
+config WIFI_SIM_CONFDIR
+ string "Virt WiFi configuration directory"
+ default "/etc/wifi"
+ depends on DRIVERS_WIFI_SIM
+ ---help---
+ Provides the full path to location in the file system where WiFi-SIM
+ BSS configuration will be accessed. This is a string and should not
+ include any trailing '/'.
+
endif # NETDEVICES
diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs
index c1f65a214d..1efd873f68 100644
--- a/drivers/net/Make.defs
+++ b/drivers/net/Make.defs
@@ -93,6 +93,10 @@ endif
endif
+ifeq ($(CONFIG_DRIVERS_WIFI_SIM),y)
+ CSRCS += wifi_sim.c
+endif
+
# Include network build support
DEPPATH += --dep-path net
diff --git a/drivers/net/wifi_sim.c b/drivers/net/wifi_sim.c
new file mode 100644
index 0000000000..a32bfeed75
--- /dev/null
+++ b/drivers/net/wifi_sim.c
@@ -0,0 +1,1946 @@
+/****************************************************************************
+ * drivers/net/wifi_sim.c
+ *
+ * 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 <debug.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <netinet/if_ether.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/ip.h>
+#include <nuttx/wireless/ieee80211/ieee80211.h>
+#include <nuttx/virtio/virtio.h>
+#include <netpacket/netlink.h>
+#include <nuttx/net/netlink.h>
+
+#include <nuttx/net/wifi_sim.h>
+#include <nuttx/fs/fs.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BSS_FILE_NAME "bss"
+#define BSS_FILE_PATH CONFIG_WIFI_SIM_CONFDIR "/" BSS_FILE_NAME
+
+#define SSID_MAX_LEN 32
+
+#define IEEE80211_CAP_PRIVACY 0x0010
+
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs).
+ */
+
+#define WLAN_SUPP_RATES_MAX 32
+
+#define WLAN_DEFAULT_TXPOWER 20
+
+#define LOWERDEV2WIFIDEV(dev) \
+ ((FAR struct wifi_sim_s *)((FAR struct wifi_sim_lowerhalf_s *)dev)->wifi)
+
+#define CHAN2G(freq) \
+ { \
+ .band = WLAN_80211_BAND_2GHZ, \
+ .center_freq = (freq), \
+ }
+
+#define CHAN5G(freq) \
+ { \
+ .band = WLAN_80211_BAND_5GHZ, \
+ .center_freq = (freq), \
+ }
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum WLAN_ALG_E
+{
+ WLAN_ALG_NONE,
+ WLAN_ALG_WEP,
+ WLAN_ALG_TKIP,
+ WLAN_ALG_CCMP,
+ WLAN_ALG_BIP_CMAC_128,
+ WLAN_ALG_GCMP,
+ WLAN_ALG_SMS4,
+ WLAN_ALG_KRK,
+ WLAN_ALG_GCMP_256,
+ WLAN_ALG_CCMP_256,
+ WLAN_ALG_BIP_GMAC_128,
+ WLAN_ALG_BIP_GMAC_256,
+ WLAN_ALG_BIP_CMAC_256
+};
+
+enum WLAN_HW_MODE_E
+{
+ WLAN_HW_MODE_IEEE80211B,
+ WLAN_HW_MODE_IEEE80211G,
+ WLAN_HW_MODE_IEEE80211A,
+ WLAN_HW_MODE_IEEE80211AD,
+ WLAN_HW_MODE_IEEE80211ANY,
+ WLAN_HW_MODES
+};
+
+/* enum WLAN_CHAN_WIDTH_E - Channel width definitions */
+
+enum WLAN_CHAN_WIDTH_E
+{
+ WLAN_CHAN_WIDTH_20_NOHT,
+ WLAN_CHAN_WIDTH_20,
+ WLAN_CHAN_WIDTH_40,
+ WLAN_CHAN_WIDTH_80,
+ WLAN_CHAN_WIDTH_80P80,
+ WLAN_CHAN_WIDTH_160,
+ WLAN_CHAN_WIDTH_2160,
+ WLAN_CHAN_WIDTH_4320,
+ WLAN_CHAN_WIDTH_6480,
+ WLAN_CHAN_WIDTH_8640,
+ WLAN_CHAN_WIDTH_320,
+ WLAN_CHAN_WIDTH_UNKNOWN
+};
+
+enum WLAN_80211_BAND_E
+{
+ WLAN_80211_BAND_2GHZ,
+ WLAN_80211_BAND_5GHZ,
+ WLAN_80211_BAND_6GHZ,
+ WLAN_80211_BAND_NUMS
+};
+
+enum WLAN_SCAN_STATE_E
+{
+ WLAN_SCAN_STATE_SCANNING,
+ WLAN_SCAN_STATE_DONE,
+};
+
+enum WLAN_STA_STATE_E
+{
+ WLAN_STA_STATE_INIT,
+ WLAN_STA_STATE_CONNECTING,
+ WLAN_STA_STATE_CONNECTED,
+};
+
+enum WLAN_STA_CONNERR_E
+{
+ WLAN_STA_CONNERR_NO_BSS,
+ WLAN_STA_CONNERR_NO_PSK,
+ WLAN_STA_CONNERR_WRONG_KEY,
+ WLAN_STA_CONNERR_FAILED,
+};
+
+/* for scan results */
+
+struct iw_scan_result_s
+{
+ int total_len;
+ int cur_len;
+ FAR char *buf; /* iwr->u.data.pointer */
+};
+
+/* channel */
+
+struct wlan_channel_s
+{
+ enum WLAN_80211_BAND_E band;
+ uint32_t center_freq;
+};
+
+struct wifi_sim_bss_s
+{
+ char bssid[ETH_ALEN]; /* bss BSSID */
+ uint16_t capability; /* Capability information */
+ char ssid[SSID_MAX_LEN + 1]; /* Capability information */
+ uint8_t ssid_len; /* the length of ssid */
+ int16_t RSSI; /* receive signal strength (in dBm) */
+ int8_t phy_noise; /* noise (in dBm) */
+ int16_t snr; /* average SNR of during frame reception */
+ uint32_t freq; /* 802.11N BSS frequency */
+ uint8_t flags; /* flags */
+ char password[64]; /* password */
+ char security[128]; /* security type */
+};
+
+struct wifi_sim_sta_info_s
+{
+ uint16_t aid;
+ char mac_addr[ETH_ALEN];
+ uint16_t capability; /* Capability information */
+ int auth_alg;
+ uint8_t supported_rates[WLAN_SUPP_RATES_MAX];
+ int supported_rates_len;
+ uint8_t qosinfo;
+ int16_t RSSI; /* receive signal strength (in dBm) */
+ uint32_t connected_time; /* units: seconds */
+ int16_t deauth_reason;
+ int16_t disassoc_reason;
+};
+
+struct wifi_sim_s
+{
+ FAR struct netdev_lowerhalf_s *lower;
+
+ char ssid[SSID_MAX_LEN + 1];
+ char bssid[ETH_ALEN];
+ uint8_t mode; /* IW_MODE_INFRA/ IW_MODE_MASTER */
+ enum WLAN_HW_MODE_E hw_mode; /* for hw mode */
+ enum WLAN_CHAN_WIDTH_E band;
+ uint16_t channel;
+ uint32_t freq;
+ char password[64];
+ int key_mgmt;
+ int proto;
+ int auth_alg;
+ int pairwise_chiper;
+ int group_cipher;
+
+ uint32_t bitrate;
+ int32_t txpower;
+ char country[4];
+ int8_t sensitivity;
+
+ bool psk_flag; /* for psk, 0: unset, 1: set */
+ uint8_t ssid_flag; /* for ssid, 0: unset, 1: set ssid
+ * 2: set bssid */
+ enum WLAN_STA_STATE_E state;
+ enum WLAN_SCAN_STATE_E scan_state;
+ uint16_t status_code; /* status code */
+ uint16_t reason_code; /* deauth and disassoc reason */
+ uint16_t error_code; /* connect error reason */
+
+ FAR struct wifi_sim_bss_s *connected_ap; /* for sta mode */
+};
+
+/* for wireless event */
+
+struct wireless_event_s
+{
+ struct nlmsghdr hdr; /* netlink message header */
+ struct ifinfomsg iface; /* interface info */
+
+ struct rtattr attrevent; /* IFLA_WIRELESS */
+ struct iw_event event; /* wireless event */
+};
+
+struct wireless_event_list_s
+{
+ sq_entry_t flink;
+ struct wireless_event_s payload;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int wifidriver_connect(FAR struct netdev_lowerhalf_s *dev);
+static int wifidriver_disconnect(FAR struct netdev_lowerhalf_s *dev);
+static int wifidriver_essid(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_bssid(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_passwd(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_mode(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_auth(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_freq(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_bitrate(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_txpower(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_country(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_sensitivity(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_scan(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set);
+static int wifidriver_range(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr);
+
+static int wifidriver_get_bssinfo(FAR struct wifi_sim_bss_s *bss_info,
+ FAR char *buf, int len);
+static int wifidriver_start_disconnect(FAR struct wifi_sim_s *wifidev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct wlan_channel_s wifi_sim_channels_2ghz[] =
+{
+ CHAN2G(2412), /* Channel 1 */
+ CHAN2G(2417), /* Channel 2 */
+ CHAN2G(2422), /* Channel 3 */
+ CHAN2G(2427), /* Channel 4 */
+ CHAN2G(2432), /* Channel 5 */
+ CHAN2G(2437), /* Channel 6 */
+ CHAN2G(2442), /* Channel 7 */
+ CHAN2G(2447), /* Channel 8 */
+ CHAN2G(2452), /* Channel 9 */
+ CHAN2G(2457), /* Channel 10 */
+ CHAN2G(2462), /* Channel 11 */
+ CHAN2G(2467), /* Channel 12 */
+ CHAN2G(2472), /* Channel 13 */
+ CHAN2G(2484), /* Channel 14 */
+};
+
+static const struct wlan_channel_s wifi_sim_channels_5ghz[] =
+{
+ CHAN5G(5180), /* Channel 36 */
+ CHAN5G(5200), /* Channel 40 */
+ CHAN5G(5220), /* Channel 44 */
+ CHAN5G(5240), /* Channel 48 */
+ CHAN5G(5260), /* Channel 52 */
+ CHAN5G(5280), /* Channel 56 */
+ CHAN5G(5300), /* Channel 60 */
+ CHAN5G(5320), /* Channel 64 */
+ CHAN5G(5745), /* Channel 149 */
+ CHAN5G(5765), /* Channel 153 */
+ CHAN5G(5785), /* Channel 157 */
+ CHAN5G(5805), /* Channel 161 */
+ CHAN5G(5825), /* Channel 165 */
+};
+
+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
+ ****************************************************************************/
+
+/* utils */
+
+static int mac_addr_a2n(FAR unsigned char *mac_addr, FAR char *arg)
+{
+ int i;
+
+ for (i = 0; i < ETH_ALEN ; i++)
+ {
+ int temp;
+ FAR 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 void mac_addr_n2a(FAR char *mac_addr, FAR 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;
+ }
+ }
+}
+
+/* wifi interfaces */
+
+static int wifi_send_event(FAR struct wifi_sim_s *wifidev,
+ unsigned int cmd, FAR union iwreq_data *wrqu)
+{
+ FAR struct net_driver_s *dev = &wifidev->lower->netdev;
+ FAR struct wireless_event_list_s *alloc;
+ FAR struct wireless_event_s *wev;
+
+ DEBUGASSERT(dev != NULL);
+
+ int up = IFF_IS_UP(dev->d_flags);
+
+ /* Allocate the response buffer */
+
+ alloc = (FAR struct wireless_event_list_s *)
+ kmm_zalloc(RTA_SPACE(sizeof(struct wireless_event_list_s)));
+ if (alloc == NULL)
+ {
+ nerr("ERROR: Failed to allocate wifi event buffer.\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize the response buffer */
+
+ wev = &alloc->payload;
+
+ wev->hdr.nlmsg_len = sizeof(struct wireless_event_s);
+ wev->hdr.nlmsg_type = up ? RTM_NEWLINK : RTM_DELLINK;
+ wev->hdr.nlmsg_flags = 0;
+ wev->hdr.nlmsg_seq = 0;
+ wev->hdr.nlmsg_pid = 0;
+
+ wev->iface.ifi_family = AF_UNSPEC;
+ wev->iface.ifi_type = ARPHRD_IEEE80211;
+#ifdef CONFIG_NETDEV_IFINDEX
+ wev->iface.ifi_index = dev->d_ifindex;
+#endif
+ wev->iface.ifi_flags = dev->d_flags;
+ wev->iface.ifi_change = 0;
+
+ /* add wireless event info */
+
+ wev->attrevent.rta_len = RTA_SPACE(sizeof(struct iw_event));
+ wev->attrevent.rta_type = IFLA_WIRELESS;
+ wev->event.len = sizeof(union iwreq_data);
+ wev->event.cmd = cmd;
+
+ memset(&wev->event.u, 0, sizeof(union iwreq_data));
+ memcpy(&wev->event.u, ((FAR char *) wrqu), sizeof(union iwreq_data));
+
+ netlink_add_broadcast(RTNLGRP_LINK,
+ (FAR struct netlink_response_s *)alloc);
+ return OK;
+}
+
+static int read_bss_config(FAR char *buf, size_t len, FAR char *path)
+{
+ struct file filep;
+ int ret;
+
+ ret = file_open(&filep, path, O_RDWR);
+ if (ret < 0)
+ {
+ nerr("open error");
+ return ret;
+ }
+
+ ret = file_read(&filep, buf, len);
+ if (ret == len)
+ {
+ ret = -E2BIG;
+ }
+ else if (ret > 0)
+ {
+ buf[ret] = '\0';
+ ninfo("content: %s", buf);
+ }
+
+ file_close(&filep);
+
+ return ret;
+}
+
+#if 0
+uint32_t wifi_chan_to_freq_mhz(int chan, enum WLAN_80211_BAND_E band)
+{
+ /* see 802.11 17.3.8.3.2 and Annex J
+ * there are overlapping channel numbers in 5GHz and 2GHz bands
+ */
+
+ if (chan <= 0)
+ {
+ return 0; /* not supported */
+ }
+
+ switch (band)
+ {
+ case WLAN_80211_BAND_2GHZ:
+ if (chan == 14)
+ {
+ return (2484);
+ }
+ else if (chan < 14)
+ {
+ return (2407 + chan * 5);
+ }
+ break;
+ case WLAN_80211_BAND_5GHZ:
+ if (chan >= 182 && chan <= 196)
+ {
+ return (4000 + chan * 5);
+ }
+ else
+ {
+ return (5000 + chan * 5);
+ }
+ break;
+ case WLAN_80211_BAND_6GHZ:
+
+ /* see 802.11ax D6.1 27.3.23.2 */
+
+ if (chan == 2)
+ {
+ return (5935);
+ }
+
+ if (chan <= 233)
+ {
+ return (5950 + chan * 5);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0; /* not supported */
+}
+#endif
+
+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 FAR 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 FAR 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 "WPA2";
+ default:
+ nerr("ERROR: Failed to transfer wifi auth: %d", auth);
+ return NULL;
+ }
+}
+
+/* implement iw_ops */
+
+static FAR struct wifi_sim_bss_s *select_bss(FAR struct wifi_sim_s *sta,
+ FAR char *bss_buf)
+{
+ char bss[256];
+ FAR char *s;
+ FAR char *p;
+ struct wifi_sim_bss_s bss_info;
+ FAR struct wifi_sim_bss_s *sbss = NULL;
+ bool bss_found = false;
+
+ for (p = bss_buf; *p != '\0'; p++)
+ {
+ s = p;
+ while (*p != '\n')
+ {
+ p++;
+ }
+
+ memset(bss, 0, sizeof(bss));
+ memcpy(bss, s, p - s + 1);
+ wifidriver_get_bssinfo(&bss_info, bss, strlen(bss));
+
+ /* compare bssid or essid, and security */
+
+ if ((sta->ssid_flag == 2 && !memcmp(sta->bssid, bss_info.bssid, 6)) ||
+ (sta->ssid_flag == 1 && !memcmp(sta->ssid, bss_info.ssid, 32)))
+ {
+ /* cmp security */
+
+ if (sta->psk_flag == 0)
+ {
+ if (!strstr(bss_info.security, "WPA") &&
+ !strstr(bss_info.security, "WEP"))
+ {
+ bss_found = true;
+ }
+ else
+ {
+ nerr("security doesn't match");
+ }
+
+ break;
+ }
+ else if (get_cipherstr(sta->pairwise_chiper) &&
+ strstr(bss_info.security,
+ get_cipherstr(sta->pairwise_chiper)))
+ {
+ bss_found = true;
+ break;
+ }
+ else
+ {
+ nerr("security doesn't match");
+ }
+ }
+ }
+
+ if (bss_found)
+ {
+ sbss = malloc(sizeof(struct wifi_sim_bss_s));
+ if (sbss == NULL)
+ {
+ nerr("select bss malloc failed!");
+ return NULL;
+ }
+
+ memcpy(sbss, &bss_info, sizeof(struct wifi_sim_bss_s));
+ }
+ else
+ {
+ nerr("No BSS match.");
+ }
+
+ return sbss;
+}
+
+static int verify_password(FAR struct wifi_sim_s *sta,
+ FAR struct wifi_sim_bss_s *bss)
+{
+ int ret = ERROR;
+
+ if (sta->psk_flag == 0)
+ {
+ ret = OK;
+ }
+ else if (!memcmp(sta->password, bss->password, strlen(sta->password)))
+ {
+ ret = OK;
+ }
+
+ return ret;
+}
+
+static int get_bss_from_file(FAR char **rbuf)
+{
+ int ret;
+ int size = 4096;
+ FAR char *p;
+
+ *rbuf = malloc(size * sizeof(char));
+ if (rbuf == NULL)
+ {
+ nerr("malloc failed!\n");
+ return -ENOMEM;
+ }
+
+redo:
+ ret = read_bss_config(*rbuf, size, BSS_FILE_PATH);
+ if (ret == -E2BIG)
+ {
+ size += 1024;
+ p = realloc(*rbuf, size);
+ if (p == NULL)
+ {
+ nerr("read bss faied in realloc!\n");
+ free(rbuf);
+ return -ENOMEM;
+ }
+
+ *rbuf = p;
+ goto redo;
+ }
+ else if (ret < 0)
+ {
+ nerr("read bss failed\n");
+ return ret;
+ }
+
+ rbuf[ret] = '\0';
+
+ return ret;
+}
+
+static bool wifidriver_sta_is_connected(FAR struct wifi_sim_s *wifidev)
+{
+ return (wifidev->state == WLAN_STA_STATE_CONNECTED);
+}
+
+static int wifidriver_start_connect(FAR struct wifi_sim_s *wifidev)
+{
+ int ret;
+ FAR char *bss_buf = NULL;
+ FAR struct wifi_sim_bss_s *bss_info;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ /* If wlan is connected, should be disconnect before connectting. */
+
+ /* 1. check and disconnect */
+
+ if (wifidev->state == WLAN_STA_STATE_CONNECTED)
+ {
+ wifidriver_start_disconnect(wifidev);
+ wifidev->state = WLAN_STA_STATE_CONNECTING;
+ }
+
+ /* 2. get_bss, match (bssid/essid, security) */
+
+ ret = get_bss_from_file(&bss_buf);
+ if (ret < 0 || bss_buf == NULL)
+ {
+ goto error;
+ }
+
+ bss_info = select_bss(wifidev, bss_buf);
+ if (bss_info == NULL)
+ {
+ nerr("select no bss.");
+ wifidev->error_code = WLAN_STA_CONNERR_NO_BSS;
+
+ ret = ERROR;
+ goto error;
+ }
+
+ /* 3. verify the password and connect to the bss */
+
+ ret = verify_password(wifidev, bss_info);
+ if (ret == OK)
+ {
+ union iwreq_data wrqu;
+
+ wifidev->state = WLAN_STA_STATE_CONNECTED;
+ wifidev->status_code = WLAN_STATUS_SUCCESS;
+ wifidev->connected_ap = bss_info;
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, bss_info->bssid, ETH_ALEN);
+ wifi_send_event(wifidev, SIOCGIWAP, &wrqu);
+ }
+ else
+ {
+ wifidev->reason_code = WLAN_REASON_DEAUTH_LEAVING;
+ wifidev->error_code = WLAN_STA_CONNERR_WRONG_KEY;
+ free(bss_info);
+
+ ret = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ }
+
+error:
+ free(bss_buf);
+ if (ret != OK)
+ {
+ wifidev->state = WLAN_STA_STATE_INIT;
+ }
+
+ wifidev->ssid_flag = 0;
+
+ /* Enshure that the default is non-encrypted. */
+
+ if (wifidev->psk_flag)
+ {
+ wifidev->psk_flag = 0;
+ }
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_start_disconnect(FAR struct wifi_sim_s *wifidev)
+{
+ int ret;
+ union iwreq_data wrqu;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ if (wifidev->state == WLAN_STA_STATE_CONNECTED)
+ {
+ /* free the connected_ap */
+
+ free(wifidev->connected_ap);
+
+ netdev_lower_carrier_off(wifidev->lower);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wifi_send_event(wifidev, SIOCGIWAP, &wrqu);
+ }
+
+ if (wifidev->psk_flag == 0)
+ {
+ memset(wifidev->password, 0, sizeof(wifidev->password));
+ wifidev->pairwise_chiper = IW_AUTH_CIPHER_NONE;
+ }
+
+ wifidev->state = WLAN_STA_STATE_INIT;
+ ret = OK;
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_get_mode(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ pwrq->u.mode = wifidev->mode;
+ ninfo("get %s mode", wifidev->lower->netdev.d_ifname);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+static int wifidriver_set_mode(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (pwrq->u.mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ wifidev->mode = pwrq->u.mode;
+
+ /* default country code CN */
+
+ memcpy(wifidev->country, "CN", 2);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+static int wifidriver_set_country(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ memcpy(wifidev->country, pwrq->u.data.pointer,
+ pwrq->u.data.length);
+ ninfo("set country is %s\n", wifidev->country);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_country(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ pwrq->u.data.length = strlen(wifidev->country);
+ memcpy(pwrq->u.data.pointer, wifidev->country,
+ pwrq->u.data.length);
+ ninfo("set country is %s\n", wifidev->country);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_sensitivity(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ if (wifidriver_sta_is_connected(wifidev))
+ {
+ pwrq->u.sens.value = -wifidev->connected_ap->RSSI;
+ }
+
+ ninfo("get rssi is %d\n", pwrq->u.sens.value);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+int wifidriver_set_freq(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ int ret;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ ret = freq_to_channel(pwrq->u.freq.m);
+ if (ret > 0)
+ {
+ wifidev->channel = ret;
+ wifidev->freq = pwrq->u.freq.m;
+ ninfo("set channel is %d\n", ret);
+ }
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_get_freq(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ if (wifidriver_sta_is_connected(wifidev))
+ {
+ pwrq->u.freq.flags = IW_FREQ_FIXED;
+ pwrq->u.freq.e = 0;
+ pwrq->u.freq.m = wifidev->connected_ap->freq;
+ }
+ else
+ {
+ pwrq->u.freq.flags = IW_FREQ_AUTO;
+ pwrq->u.freq.e = 0;
+ pwrq->u.freq.m = 2412;
+ }
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ {
+ pwrq->u.freq.flags = IW_FREQ_FIXED;
+ pwrq->u.freq.e = 0;
+ pwrq->u.freq.m = wifidev->freq;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+int wifidriver_set_txpower(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ int ret;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ wifidev->txpower = pwrq->u.txpower.value;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_get_txpower(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ pwrq->u.txpower.value = wifidev->txpower ? wifidev->txpower :
+ WLAN_DEFAULT_TXPOWER;
+
+ pwrq->u.txpower.fixed = 0;
+ pwrq->u.txpower.disabled = 0;
+ pwrq->u.txpower.flags = IW_TXPOW_DBM;
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_bitrate(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ if (wifidev->state != WLAN_STA_STATE_CONNECTED)
+ {
+ pwrq->u.bitrate.fixed = IW_FREQ_AUTO;
+ }
+ else
+ {
+ pwrq->u.bitrate.fixed = IW_FREQ_FIXED;
+
+ /* default 2streams 40MHz */
+
+ pwrq->u.bitrate.value = 150;
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_range(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ int k;
+ int i;
+ FAR struct iw_range *range = (FAR struct iw_range *)pwrq->u.data.pointer;
+
+ /* default in china. */
+
+ /* Add 2.4G channel */
+
+ range->num_frequency = nitems(wifi_sim_channels_2ghz);
+ 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 = wifi_sim_channels_2ghz[k - 1].center_freq;
+ }
+
+ /* Add 5GHz channels */
+
+ range->num_frequency += nitems(wifi_sim_channels_5ghz);
+ for (i = 0; k <= range->num_frequency; k++)
+ {
+ range->freq[k - 1].i = k;
+ range->freq[k - 1].e = 0;
+ range->freq[k - 1].m = wifi_sim_channels_5ghz[i++].center_freq;
+ }
+
+ return OK;
+}
+
+static int wifidriver_start_scan(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ wifidev->scan_state = WLAN_SCAN_STATE_SCANNING;
+ ninfo("scan %s\n", BSS_FILE_PATH);
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return OK;
+}
+
+static int copy_scan_results(FAR struct iw_scan_result_s *scan_req,
+ FAR struct wifi_sim_bss_s *info)
+{
+ int need_len;
+ FAR char *pointer;
+ FAR 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 = (FAR struct iw_event *)pointer;
+ iwe->cmd = SIOCGIWAP;
+ iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(&iwe->u.ap_addr.sa_data, info->bssid, IFHWADDRLEN);
+ iwe->len = IW_EV_LEN(ap_addr);
+ pointer += iwe->len;
+
+ /* 2.Copy ESSID */
+
+ iwe = (FAR 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 = (FAR 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 = (FAR 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 = (FAR 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 = (FAR 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 wifidriver_get_bssinfo(FAR struct wifi_sim_bss_s *bss_info,
+ FAR char *buf, int len)
+{
+ unsigned char bssid[ETH_ALEN];
+ char str[128];
+ FAR char *p = NULL;
+ FAR 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, 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;
+ memcpy(bss_info->security, str, p - s);
+ }
+ break;
+
+ case 4:
+ {
+ /* ssid */
+
+ memcpy(bss_info->ssid, str, p - s);
+ bss_info->ssid_len = p - s;
+ }
+ break;
+
+ case 5:
+ {
+ /* password */
+
+ memcpy(bss_info->password, str, p - s);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ninfo("\n");
+
+ return OK;
+}
+
+static int get_scan_results(FAR struct wifi_sim_s *wifidev,
+ FAR struct iw_scan_result_s *scan_reqs)
+{
+ int ret;
+ FAR char *rbuf;
+ char bss[128];
+ FAR char *p;
+ FAR char *s;
+ struct wifi_sim_bss_s bss_info;
+
+ ret = get_bss_from_file(&rbuf);
+ if (ret < 0)
+ {
+ if (rbuf)
+ {
+ free(rbuf);
+ }
+
+ return ret;
+ }
+
+ 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);
+
+ wifidriver_get_bssinfo(&bss_info, bss, strlen(bss));
+ ret = copy_scan_results(scan_reqs, &bss_info);
+ if (ret < 0)
+ {
+ break;
+ }
+ }
+
+ free(rbuf);
+
+ return ret;
+}
+
+static int wifidriver_scan_result(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ struct iw_scan_result_s scan_req;
+ int ret = 0;
+
+ if (wifidev->mode == IW_MODE_MASTER)
+ {
+ return OK;
+ }
+ else if (wifidev->mode == IW_MODE_INFRA)
+ {
+ if (wifidev->scan_state == WLAN_SCAN_STATE_SCANNING)
+ {
+ wifidev->scan_state = WLAN_SCAN_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ 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_essid(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ case IW_MODE_MASTER:
+ {
+ memset(wifidev->ssid, 0, sizeof(wifidev->ssid));
+ memcpy(wifidev->ssid, pwrq->u.essid.pointer, pwrq->u.essid.length);
+ wifidev->ssid_flag = 1;
+ ninfo("set essid = %s\n", wifidev->ssid);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_essid(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ FAR struct iw_point *essid = &pwrq->u.essid;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ /* get essid */
+
+ pwrq->u.essid.length = strlen(wifidev->ssid);
+ memcpy(pwrq->u.essid.pointer, wifidev->ssid, pwrq->u.essid.length);
+
+ ninfo("get essid = %s\n", wifidev->ssid);
+
+ /* get state */
+
+ if (wifidev->state == WLAN_STA_STATE_CONNECTED)
+ {
+ essid->flags = IW_ESSID_ON;
+ }
+ else
+ {
+ essid->flags = IW_ESSID_OFF;
+ }
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
+static int wifidriver_set_bssid(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ FAR struct sockaddr *sockaddr = &pwrq->u.ap_addr;
+ FAR unsigned char *pdata = (FAR unsigned char *)sockaddr->sa_data;
+ char bssid_str[20];
+ int ret;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ memcpy(wifidev->bssid, pdata, ETH_ALEN);
+ mac_addr_n2a(bssid_str, pdata);
+ ninfo("set bssid = %s\n", bssid_str);
+
+ wifidev->ssid_flag = 2;
+ ret = OK;
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_get_bssid(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ FAR struct sockaddr *sockaddr = &pwrq->u.ap_addr;
+ FAR unsigned char *pdata = (FAR unsigned char *)sockaddr->sa_data;
+ int ret;
+
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ {
+ if (wifidriver_sta_is_connected(wifidev))
+ {
+ memcpy(pdata, wifidev->connected_ap->bssid, ETH_ALEN);
+ ret = OK;
+ }
+ else
+ {
+ ret = -ENOTTY;
+ }
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wifidriver_set_auth(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ int flag = pwrq->u.param.flags & IW_AUTH_INDEX;
+ int value = pwrq->u.param.value;
+
+ if (wifidev->mode != IW_MODE_INFRA)
+ {
+ return -ENOSYS;
+ }
+
+ switch (flag)
+ {
+ case IW_AUTH_WPA_VERSION:
+ {
+ /* record the value */
+
+ wifidev->proto = value >> 1;
+
+ ninfo("proto=%s\n", get_authstr(value));
+ }
+ break;
+
+ case IW_AUTH_CIPHER_PAIRWISE:
+ {
+ /* record the value */
+
+ wifidev->pairwise_chiper = value;
+
+ ninfo("pairwise=%s\n", get_cipherstr(value));
+ }
+ break;
+
+ default:
+ nerr("ERROR: Unknown cmd %d\n", flag);
+ return -ENOSYS;
+ }
+
+ return OK;
+}
+
+static int wifidriver_get_auth(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ switch (wifidev->mode)
+ {
+ case IW_MODE_INFRA:
+ break;
+ case IW_MODE_MASTER:
+ break;
+ default:
+ break;
+ }
+
+ return OK;
+}
+
+static int wifidriver_set_psk(FAR struct wifi_sim_s *wifidev,
+ FAR struct iwreq *pwrq)
+{
+ FAR struct iw_encode_ext *ext;
+ int ret = OK;
+
+ ext = (FAR struct iw_encode_ext *)pwrq->u.encoding.pointer;
+
+ /* 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:
+ {
+ wifidev->auth_alg = ext->alg;
+ memset(wifidev->password, 0, sizeof(wifidev->password));
+ memcpy(wifidev->password, ext->key, ext->key_len);
+
+ ninfo("psk=%s, key_len= %d, alg=%u\n", wifidev->password,
+ ext->key_len, ext->alg);
+
+ /* Set the psk flag for security ap. */
+
+ wifidev->psk_flag = 1;
+ }
+ break;
+
+ case IW_MODE_MASTER:
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret ;
+}
+
+/* iw_ops */
+
+static int wifidriver_connect(FAR struct netdev_lowerhalf_s *dev)
+{
+ int ret;
+
+ ret = wifidriver_start_connect(LOWERDEV2WIFIDEV(dev));
+ if (ret >= 0)
+ {
+ ret = netdev_lower_carrier_on(dev);
+ }
+
+ return ret;
+}
+
+static int wifidriver_disconnect(FAR struct netdev_lowerhalf_s *dev)
+{
+ return wifidriver_start_disconnect(LOWERDEV2WIFIDEV(dev));
+}
+
+static int wifidriver_essid(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_essid(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_essid(wifidev, iwr);
+ }
+}
+
+static int wifidriver_bssid(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ int ret;
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ ret = wifidriver_set_bssid(wifidev, iwr);
+ if (ret >= 0)
+ {
+ ret = wifidriver_start_connect(wifidev);
+ }
+ }
+ else
+ {
+ ret = wifidriver_get_bssid(wifidev, iwr);
+ }
+
+ return ret;
+}
+
+static int wifidriver_passwd(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ if (set)
+ {
+ return wifidriver_set_psk(LOWERDEV2WIFIDEV(dev), iwr);
+ }
+ else
+ {
+ return -ENOTTY;
+ }
+}
+
+static int wifidriver_mode(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_mode(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_mode(wifidev, iwr);
+ }
+}
+
+static int wifidriver_auth(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_auth(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_auth(wifidev, iwr);
+ }
+}
+
+static int wifidriver_freq(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_freq(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_freq(wifidev, iwr);
+ }
+}
+
+static int wifidriver_bitrate(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return -ENOTTY;
+ }
+ else
+ {
+ return wifidriver_get_bitrate(wifidev, iwr);
+ }
+}
+
+static int wifidriver_txpower(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_txpower(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_txpower(wifidev, iwr);
+ }
+}
+
+static int wifidriver_country(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_set_country(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_get_country(wifidev, iwr);
+ }
+}
+
+static int wifidriver_sensitivity(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return -ENOTTY;
+ }
+ else
+ {
+ return wifidriver_get_sensitivity(wifidev, iwr);
+ }
+}
+
+static int wifidriver_scan(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr, bool set)
+{
+ FAR struct wifi_sim_s *wifidev = LOWERDEV2WIFIDEV(dev);
+
+ if (set)
+ {
+ return wifidriver_start_scan(wifidev, iwr);
+ }
+ else
+ {
+ return wifidriver_scan_result(wifidev, iwr);
+ }
+}
+
+static int wifidriver_range(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct iwreq *iwr)
+{
+ return wifidriver_get_range(LOWERDEV2WIFIDEV(dev), iwr);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: wifi_sim_init
+ ****************************************************************************/
+
+int wifi_sim_init(FAR struct wifi_sim_lowerhalf_s *netdev)
+{
+ FAR struct wifi_sim_s *priv;
+
+ priv = kmm_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ {
+ nerr("virt wifi driver priv alloc failed\n");
+ return -ENOMEM;
+ }
+
+ netdev->lower.iw_ops = &g_iw_ops;
+ priv->lower = &netdev->lower;
+ netdev->wifi = priv;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: wifi_sim_remove
+ ****************************************************************************/
+
+void wifi_sim_remove(FAR struct wifi_sim_lowerhalf_s *netdev)
+{
+ FAR struct wifi_sim_s *sta = (FAR struct wifi_sim_s *)netdev->wifi;
+
+ if (sta && sta->state == WLAN_STA_STATE_CONNECTED)
+ {
+ wifidriver_start_disconnect(sta);
+ }
+
+ kmm_free(netdev->wifi);
+}
+
diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c
index c1908e7dc7..5d324388f3 100644
--- a/drivers/virtio/virtio-net.c
+++ b/drivers/virtio/virtio-net.c
@@ -32,6 +32,7 @@
#include <nuttx/net/ip.h>
#include <nuttx/net/netdev_lowerhalf.h>
#include <nuttx/virtio/virtio.h>
+#include <nuttx/net/wifi_sim.h>
#include "virtio-net.h"
@@ -96,9 +97,16 @@ begin_packed_struct struct virtio_net_config_s
struct virtio_net_priv_s
{
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ /* wifi device information, which includes the netdev lowerhalf */
+
+ struct wifi_sim_lowerhalf_s lower;
+#else
+
/* This holds the information visible to the NuttX network */
struct netdev_lowerhalf_s lower; /* The netdev lowerhalf */
+#endif
/* Virtio device information */
@@ -147,7 +155,8 @@ static int virtio_net_rmmac(FAR struct netdev_lowerhalf_s *dev,
FAR const uint8_t *mac);
#endif
#ifdef CONFIG_NETDEV_IOCTL
-static int virtio_net_ioctl(FAR struct netdev_lowerhalf_s *dev);
+static int virtio_net_ioctl(FAR struct netdev_lowerhalf_s *dev,
+ int cmd, unsigned long arg);
#endif
static int virtio_net_probe(FAR struct virtio_device *vdev);
@@ -303,7 +312,16 @@ static int virtio_net_ifup(FAR struct netdev_lowerhalf_s *dev)
virtqueue_enable_cb(priv->vdev->vrings_info[VIRTIO_NET_RX].vq);
virtio_net_rxfill(dev);
- return netdev_lower_carrier_on(dev);
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ if (priv->lower.wifi)
+ {
+ return OK;
+ }
+ else
+#endif
+ {
+ return netdev_lower_carrier_on(dev);
+ }
}
/****************************************************************************
@@ -322,7 +340,16 @@ static int virtio_net_ifdown(FAR struct netdev_lowerhalf_s *dev)
virtqueue_disable_cb(priv->vdev->vrings_info[i].vq);
}
- return netdev_lower_carrier_off(dev);
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ if (priv->lower.wifi)
+ {
+ return dev->iw_ops->disconnect(dev);
+ }
+ else
+#endif
+ {
+ return netdev_lower_carrier_off(dev);
+ }
}
/****************************************************************************
@@ -420,7 +447,7 @@ static netpkt_t *virtio_net_recv(FAR struct netdev_lowerhalf_s *dev)
* TODO: Find a better way to free TX buffer.
*/
- virtio_net_txfree(&priv->lower);
+ virtio_net_txfree((FAR struct netdev_lowerhalf_s *)priv);
vrtinfo("get NULL buffer\n");
return NULL;
@@ -460,7 +487,8 @@ static int virtio_net_rmmac(FAR struct netdev_lowerhalf_s *dev,
* Name: virtio_net_ioctl
****************************************************************************/
-static int virtio_net_ioctl(FAR struct netdev_lowerhalf_s *dev)
+static int virtio_net_ioctl(FAR struct netdev_lowerhalf_s *dev,
+ int cmd, unsigned long arg)
{
return -ENOTTY;
}
@@ -475,7 +503,7 @@ static void virtio_net_rxready(FAR struct virtqueue *vq)
FAR struct virtio_net_priv_s *priv = vq->vq_dev->priv;
virtqueue_disable_cb(vq);
- netdev_lower_rxready(&priv->lower);
+ netdev_lower_rxready((FAR struct netdev_lowerhalf_s *)priv);
}
/****************************************************************************
@@ -487,7 +515,7 @@ static void virtio_net_txdone(FAR struct virtqueue *vq)
FAR struct virtio_net_priv_s *priv = vq->vq_dev->priv;
virtqueue_disable_cb(vq);
- netdev_lower_txdone(&priv->lower);
+ netdev_lower_txdone((FAR struct netdev_lowerhalf_s *)priv);
}
/****************************************************************************
@@ -542,7 +570,8 @@ static int virtio_net_init(FAR struct virtio_net_priv_s *priv,
static void virtio_net_set_macaddr(FAR struct virtio_net_priv_s *priv)
{
- FAR struct net_driver_s *dev = &priv->lower.netdev;
+ FAR struct net_driver_s *dev =
+ &((FAR struct netdev_lowerhalf_s *)&priv->lower)->netdev;
FAR struct virtio_device *vdev = priv->vdev;
FAR uint8_t *mac = dev->d_mac.ether.ether_addr_octet;
@@ -602,17 +631,34 @@ static int virtio_net_probe(FAR struct virtio_device *vdev)
/* Initialize the netdev lower half */
- netdev = &priv->lower;
+ netdev = (FAR struct netdev_lowerhalf_s *)priv;
netdev->quota[NETPKT_RX] = priv->bufnum;
netdev->quota[NETPKT_TX] = priv->bufnum;
netdev->ops = &g_virtio_net_ops;
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ ret = wifi_sim_init(&priv->lower);
+ if (ret < 0)
+ {
+ goto err_with_virtqueues;
+ }
+#endif
+
/* Register the net deivce */
- ret = netdev_lower_register(netdev, NET_LL_ETHERNET);
+ ret = netdev_lower_register(netdev,
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ NET_LL_IEEE80211
+#else
+ NET_LL_ETHERNET
+#endif
+ );
if (ret < 0)
{
vrterr("netdev_lower_register failed, ret=%d\n", ret);
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ wifi_sim_remove(&priv->lower);
+#endif
goto err_with_virtqueues;
}
@@ -636,9 +682,12 @@ static void virtio_net_remove(FAR struct virtio_device *vdev)
{
FAR struct virtio_net_priv_s *priv = vdev->priv;
- netdev_lower_unregister(&priv->lower);
+ netdev_lower_unregister((FAR struct netdev_lowerhalf_s *)priv);
virtio_reset_device(vdev);
virtio_delete_virtqueues(vdev);
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+ wifi_sim_remove(&priv->lower);
+#endif
kmm_free(priv);
}
diff --git a/include/nuttx/net/wifi_sim.h b/include/nuttx/net/wifi_sim.h
new file mode 100644
index 0000000000..791a0396f2
--- /dev/null
+++ b/include/nuttx/net/wifi_sim.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * include/nuttx/net/wifi_sim.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_WIFI_SIM_H
+#define __INCLUDE_NUTTX_NET_WIFI_SIM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_DRIVERS_WIFI_SIM
+
+#include <nuttx/net/netdev_lowerhalf.h>
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+struct wifi_sim_lowerhalf_s
+{
+ /* This holds the information visible to the NuttX network */
+
+ struct netdev_lowerhalf_s lower; /* The netdev lowerhalf */
+
+ FAR void *wifi;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int wifi_sim_init(FAR struct wifi_sim_lowerhalf_s *netdev);
+void wifi_sim_remove(FAR struct wifi_sim_lowerhalf_s *netdev);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_DRIVERS_WIFI_SIM */
+#endif /* __INCLUDE_NUTTX_NET_WIFI_SIM_H */