diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 918e49a54f..ff289b2fb0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -45,6 +45,13 @@ config NETDEV_WORK_THREAD_PRIORITY ---help--- The priority of work poll thread in netdev. +config NETDEV_WIRELESS_HANDLER + bool "Support wireless handler in upper-half driver" + default y + depends on NETDEV_IOCTL + ---help--- + Enable the wireless handler support in upper-half driver. + comment "General Ethernet MAC Driver Options" config NET_RPMSG_DRV diff --git a/drivers/net/netdev_upperhalf.c b/drivers/net/netdev_upperhalf.c index caf82bb5b9..9a5e2c544a 100644 --- a/drivers/net/netdev_upperhalf.c +++ b/drivers/net/netdev_upperhalf.c @@ -537,6 +537,250 @@ static int netdev_upper_txavail(FAR struct net_driver_s *dev) return OK; } +/**************************************************************************** + * Name: netdev_upper_wireless_ioctl + * + * Description: + * Support for wireless handlers in ioctl. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_WIRELESS_HANDLER +int netdev_upper_wireless_ioctl(FAR struct netdev_lowerhalf_s *lower, + int cmd, unsigned long arg) +{ + int ret = -ENOTTY; /* Default to ENOTTY to indicate not serving. */ + FAR struct iwreq *iwr = (FAR struct iwreq *)arg; + FAR const struct wireless_ops_s *ops = lower->iw_ops; + const struct ether_addr zero = + { + }; + + /* Decode and dispatch the driver-specific IOCTL command */ + + switch (cmd) + { + case SIOCSIWENCODEEXT: /* Set encoding token & mode */ + if (ops->passwd) + { + ret = ops->passwd(lower, iwr, true); + } + break; + + case SIOCGIWENCODEEXT: /* Get encoding token & mode */ + if (ops->passwd) + { + ret = ops->passwd(lower, iwr, false); + } + break; + + case SIOCSIWESSID: /* Set ESSID */ + if (ops->essid) + { + if ((iwr->u.essid.flags == IW_ESSID_ON) || + (iwr->u.essid.flags == IW_ESSID_DELAY_ON)) + { + ret = ops->essid(lower, iwr, true); + if (ret < 0) + { + break; + } + + if (iwr->u.essid.flags == IW_ESSID_ON) + { + ret = ops->connect(lower); + if (ret < 0) + { + nerr("ERROR: Failed to connect\n"); + break; + } + } + } + else + { + ret = ops->disconnect(lower); + if (ret < 0) + { + nerr("ERROR: Failed to disconnect\n"); + break; + } + } + } + break; + + case SIOCGIWESSID: /* Get ESSID */ + if (ops->essid) + { + ret = ops->essid(lower, iwr, false); + } + break; + + case SIOCSIWAP: /* Set access point MAC addresses */ + if (ops->bssid) + { + if (memcmp(iwr->u.ap_addr.sa_data, &zero, sizeof(zero)) != 0) + { + ret = ops->bssid(lower, iwr, true); + if (ret < 0) + { + nerr("ERROR: Failed to set BSSID\n"); + break; + } + + ret = ops->connect(lower); + if (ret < 0) + { + nerr("ERROR: Failed to connect\n"); + break; + } + } + else + { + ret = ops->disconnect(lower); + if (ret < 0) + { + nerr("ERROR: Failed to disconnect\n"); + break; + } + } + } + break; + + case SIOCGIWAP: /* Get access point MAC addresses */ + if (ops->bssid) + { + ret = ops->bssid(lower, iwr, false); + } + break; + + case SIOCSIWSCAN: /* Trigger scanning */ + if (ops->scan) + { + ret = ops->scan(lower, iwr, true); + } + break; + + case SIOCGIWSCAN: /* Get scanning results */ + if (ops->scan) + { + ret = ops->scan(lower, iwr, false); + } + break; + + case SIOCSIWCOUNTRY: /* Set country code */ + if (ops->country) + { + ret = ops->country(lower, iwr, true); + } + break; + + case SIOCGIWCOUNTRY: /* Get country code */ + if (ops->country) + { + ret = ops->country(lower, iwr, false); + } + break; + + case SIOCSIWSENS: /* Set sensitivity (dBm) */ + if (ops->sensitivity) + { + ret = ops->sensitivity(lower, iwr, true); + } + break; + + case SIOCGIWSENS: /* Get sensitivity (dBm) */ + if (ops->sensitivity) + { + ret = ops->sensitivity(lower, iwr, false); + } + break; + + case SIOCSIWMODE: /* Set operation mode */ + if (ops->mode) + { + ret = ops->mode(lower, iwr, true); + } + break; + + case SIOCGIWMODE: /* Get operation mode */ + if (ops->mode) + { + ret = ops->mode(lower, iwr, false); + } + break; + + case SIOCSIWAUTH: /* Set authentication mode params */ + if (ops->auth) + { + ret = ops->auth(lower, iwr, true); + } + break; + + case SIOCGIWAUTH: /* Get authentication mode params */ + if (ops->auth) + { + ret = ops->auth(lower, iwr, false); + } + break; + + case SIOCSIWFREQ: /* Set channel/frequency (MHz) */ + if (ops->freq) + { + ret = ops->freq(lower, iwr, true); + } + break; + + case SIOCGIWFREQ: /* Get channel/frequency (MHz) */ + if (ops->freq) + { + ret = ops->freq(lower, iwr, false); + } + break; + + case SIOCSIWRATE: /* Set default bit rate (Mbps) */ + if (ops->bitrate) + { + ret = ops->bitrate(lower, iwr, true); + } + break; + + case SIOCGIWRATE: /* Get default bit rate (Mbps) */ + if (ops->bitrate) + { + ret = ops->bitrate(lower, iwr, false); + } + break; + + case SIOCSIWTXPOW: /* Set transmit power (dBm) */ + if (ops->txpower) + { + ret = ops->txpower(lower, iwr, true); + } + break; + + case SIOCGIWTXPOW: /* Get transmit power (dBm) */ + if (ops->txpower) + { + ret = ops->txpower(lower, iwr, false); + } + break; + + case SIOCGIWRANGE: /* Get range of parameters */ + if (ops->range) + { + ret = ops->range(lower, iwr); + } + break; + + default: + nerr("ERROR: Unrecognized IOCTL command: %d\n", cmd); + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_WIRELESS_HANDLER */ + /**************************************************************************** * Name: netdev_upper_ifup/ifdown/addmac/rmmac/ioctl * @@ -632,10 +876,22 @@ static int netdev_upper_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) { FAR struct netdev_upperhalf_s *upper = dev->d_private; + FAR struct netdev_lowerhalf_s *lower = upper->lower; - if (upper->lower->ops->ioctl) +#ifdef CONFIG_NETDEV_WIRELESS_HANDLER + if (lower->iw_ops) { - return upper->lower->ops->ioctl(upper->lower, cmd, arg); + int ret = netdev_upper_wireless_ioctl(lower, cmd, arg); + if (ret != -ENOTTY) + { + return ret; + } + } +#endif + + if (lower->ops->ioctl) + { + return lower->ops->ioctl(lower, cmd, arg); } return -ENOTTY; diff --git a/include/nuttx/net/netdev_lowerhalf.h b/include/nuttx/net/netdev_lowerhalf.h index 88e6ebc99d..737da56a69 100644 --- a/include/nuttx/net/netdev_lowerhalf.h +++ b/include/nuttx/net/netdev_lowerhalf.h @@ -41,6 +41,7 @@ #include #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -87,10 +88,17 @@ enum netpkt_type_e */ struct netdev_ops_s; +struct wireless_ops_s; struct netdev_lowerhalf_s { FAR const struct netdev_ops_s *ops; + /* Extended operations. */ + +#ifdef CONFIG_NETDEV_WIRELESS_HANDLER + FAR const struct wireless_ops_s *iw_ops; +#endif + /* Max # of buffer held by driver */ #ifdef CONFIG_HAVE_ATOMICS @@ -148,6 +156,46 @@ struct netdev_ops_s #endif }; +/* This structure is a set of wireless handlers, leave unsupported operations + * as NULL is OK. + */ + +#ifdef CONFIG_NETDEV_WIRELESS_HANDLER +typedef int (*iw_handler_rw)(FAR struct netdev_lowerhalf_s *dev, + FAR struct iwreq *iwr, bool set); +typedef int (*iw_handler_ro)(FAR struct netdev_lowerhalf_s *dev, + FAR struct iwreq *iwr); + +struct wireless_ops_s +{ + /* Connect / disconnect operation, should exist if essid or bssid exists */ + + int (*connect)(FAR struct netdev_lowerhalf_s *dev); + int (*disconnect)(FAR struct netdev_lowerhalf_s *dev); + + /* The following attributes need both set and get. */ + + iw_handler_rw essid; + iw_handler_rw bssid; + iw_handler_rw passwd; + iw_handler_rw mode; + iw_handler_rw auth; + iw_handler_rw freq; + iw_handler_rw bitrate; + iw_handler_rw txpower; + iw_handler_rw country; + iw_handler_rw sensitivity; + + /* Scan operation: start scan (set=1) / get scan result (set=0). */ + + iw_handler_rw scan; + + /* Get-only attributes. */ + + iw_handler_ro range; +}; +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/