drivers/net: Add wireless ops in upper-half driver

Take the idea from Linux's iw_handler array and esp32c3_wlan's wlan_ops_s, and make it a common logic of upper-half driver.

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-05-19 15:25:57 +08:00 committed by Xiang Xiao
parent a7a47621fa
commit c253bb91a2
3 changed files with 313 additions and 2 deletions

View file

@ -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

View file

@ -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;

View file

@ -41,6 +41,7 @@
#include <nuttx/net/ip.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/wireless/wireless.h>
/****************************************************************************
* 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
****************************************************************************/