wireless/bcm43xxx: add more ioctl command support

Support command:
  SIOCGIWFREQ
  SIOCGIWMODE
  SIOCSIWAP
  SIOCGIWAP
  SIOCGIWESSID
  SIOCGIWRATE
  SIOCGIWTXPOW
  SIOCGIWSENS
  SIOCGIWRANGE

Before:                                    After:
 cp> wapi show wlan0                          cp> wapi show wlan0
 wlan0 Configuration:                         wlan0 Configuration:
        IP: 192.168.31.202                           IP: 192.168.31.202
   NetMask: 255.255.255.0                       NetMask: 255.255.255.0
 ioctl(SIOCGIWFREQ): 88                       Frequency: 5785
 ERROR: wapi_get_freq() failed: -88                Flag: WAPI_FREQ_AUTO
 ioctl(SIOCGIWESSID): 88                        Channel: 157
 ERROR: wapi_get_essid() failed: -88          Frequency: 5785
 ioctl(SIOCGIWMODE): 88                           ESSID: archer5
 ERROR: wapi_get_mode() failed: -88                Flag: WAPI_ESSID_ON
 ioctl(SIOCGIWAP): 88                              Mode: WAPI_MODE_MANAGED
 ERROR: wapi_get_ap() failed: -88                    AP: ec:41:18:e0:76:7f
 ioctl(SIOCGIWRATE): 88                         BitRate: 58500
 ERROR: wapi_get_bitrate() failed: -88             Flag: WAPI_BITRATE_FIXED
 ioctl(SIOCGIWTXPOW): 88                        TxPower: 31
 ERROR: wapi_get_txpower() failed: -88             Flag: WAPI_TXPOWER_DBM
 ioctl(SIOCGIWSENS): 25                           Sense: -17

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2022-06-17 14:47:26 +08:00 committed by Xiang Xiao
parent 9c68064024
commit 2992b10fbb
4 changed files with 337 additions and 19 deletions

View file

@ -155,6 +155,32 @@ static int bcmf_wl_get_interface(FAR struct bcmf_dev_s *priv,
* Private Functions
****************************************************************************/
static int bcmf_wl_channel_to_frequency(int chan)
{
if (chan <= 0)
{
return 0;
}
else if (chan < 14)
{
return 2407 + chan * 5;
}
else if (chan == 14)
{
return 2484;
}
else if ((chan >= 36) && (chan <= 165))
{
return 5000 + chan * 5;
}
else if ((chan >= 182) && (chan <= 196))
{
return 4000 + chan * 5;
}
return 0; /* not supported */
}
FAR struct bcmf_dev_s *bcmf_allocate_device(void)
{
int ret;
@ -1358,9 +1384,9 @@ int bcmf_wl_set_auth_param(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
int bcmf_wl_set_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
int interface;
uint32_t out_len;
uint32_t value;
int interface;
interface = bcmf_wl_get_interface(priv, iwr);
@ -1369,17 +1395,257 @@ int bcmf_wl_set_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
return -EINVAL;
}
out_len = 4;
out_len = sizeof(value);
value = iwr->u.mode == IW_MODE_INFRA ? 1 : 0;
if (bcmf_cdc_ioctl(priv, interface, true,
WLC_SET_INFRA, (uint8_t *)&value, &out_len))
return bcmf_cdc_ioctl(priv, interface, true,
WLC_SET_INFRA, (uint8_t *)&value, &out_len);
}
int bcmf_wl_get_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
uint32_t infra;
int interface;
uint32_t ap;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EIO;
return -EINVAL;
}
out_len = sizeof(infra);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_INFRA, (uint8_t *)&infra, &out_len);
if (ret == OK)
{
out_len = sizeof(ap);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_AP, (uint8_t *)&ap, &out_len);
}
if (ret == OK)
{
if (infra == 0)
{
iwr->u.mode = IW_MODE_ADHOC;
}
else if (ap)
{
iwr->u.mode = IW_MODE_MASTER;
}
else
{
iwr->u.mode = IW_MODE_INFRA;
}
}
return ret;
}
int bcmf_wl_set_bssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
int interface;
int ap = 0;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
out_len = sizeof(ap);
ret = bcmf_cdc_ioctl(priv, interface, false, WLC_GET_AP,
(uint8_t *)&ap, &out_len);
if (ret == OK)
{
out_len = sizeof(struct ether_addr);
ret = bcmf_cdc_ioctl(priv, interface, true,
(ap ? WLC_SET_BSSID : WLC_REASSOC),
(uint8_t *)iwr->u.ap_addr.sa_data, &out_len);
}
return ret;
}
int bcmf_wl_get_bssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
int interface;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
iwr->u.ap_addr.sa_family = ARPHRD_ETHER;
out_len = sizeof(struct ether_addr);
return bcmf_cdc_ioctl(priv, interface, false, WLC_GET_BSSID,
(uint8_t *)iwr->u.ap_addr.sa_data, &out_len);
}
int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
channel_info_t ci;
uint32_t out_len;
int interface;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
out_len = sizeof(ci);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_CHANNEL, (uint8_t *)&ci, &out_len);
if (ret == OK)
{
iwr->u.freq.m = bcmf_wl_channel_to_frequency(ci.target_channel);
}
return ret;
}
int bcmf_wl_get_rate(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
uint32_t rate;
int interface;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
out_len = sizeof(rate);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_RATE, (uint8_t *)&rate, &out_len);
if (ret == OK)
{
iwr->u.bitrate.value = ((rate / 2) * 1000) + ((rate & 1) ? 500 : 0);
iwr->u.bitrate.fixed = 1;
}
return ret;
}
int bcmf_wl_get_txpower(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
int interface;
int radio;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
out_len = sizeof(radio);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_RADIO, (uint8_t *)&radio, &out_len);
if (ret == OK)
{
out_len = sizeof(iwr->u.txpower.value);
ret = bcmf_cdc_iovar_request(priv, interface, false,
IOVAR_STR_QTXPOWER,
(uint8_t *)&(iwr->u.txpower.value),
&out_len);
if (ret == OK)
{
iwr->u.txpower.value &= ~WL_TXPWR_OVERRIDE;
iwr->u.txpower.value /= 4;
iwr->u.txpower.fixed = 0;
iwr->u.txpower.disabled = radio;
iwr->u.txpower.flags = IW_TXPOW_DBM;
}
}
return ret;
}
int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
struct iw_range *range;
channel_info_t ci;
uint32_t out_len;
int interface;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
if (iwr->u.data.length < sizeof(struct iw_range))
{
return -EINVAL;
}
range = iwr->u.data.pointer;
memset(range, 0, sizeof(*range));
out_len = sizeof(ci);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_CHANNEL, (uint8_t *)&ci, &out_len);
if (ret == OK)
{
range->num_frequency = 1;
range->freq[0].m = bcmf_wl_channel_to_frequency(ci.target_channel);
range->freq[0].i = ci.target_channel;
}
return OK;
}
int bcmf_wl_get_rssi(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
wl_sta_rssi_t rssi;
uint32_t out_len;
int interface;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
memset(&rssi.sta_addr, 0x0, sizeof(rssi.sta_addr));
out_len = sizeof(rssi);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_RSSI, (uint8_t *)&rssi, &out_len);
if (ret == OK)
{
iwr->u.sens.value = -rssi.rssi;
}
return ret;
}
int bcmf_wl_set_encode_ext(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
int interface;
@ -1468,3 +1734,32 @@ int bcmf_wl_set_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
return OK;
}
int bcmf_wl_get_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
{
uint32_t out_len;
wlc_ssid_t ssid;
int interface;
int ret;
interface = bcmf_wl_get_interface(priv, iwr);
if (interface < 0)
{
return -EINVAL;
}
/* Configure AP SSID and trig authentication request */
out_len = sizeof(ssid);
ret = bcmf_cdc_ioctl(priv, interface, false,
WLC_GET_SSID, (uint8_t *)&ssid, &out_len);
if (ret == OK)
{
iwr->u.essid.flags = iwr->u.data.flags = 1;
iwr->u.essid.length = iwr->u.data.length = ssid.ssid_len + 1;
memcpy(iwr->u.essid.pointer, ssid.SSID, iwr->u.essid.length);
}
return ret;
}

View file

@ -151,7 +151,22 @@ int bcmf_wl_set_auth_param(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_encode_ext(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_bssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_bssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_channel(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_rate(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_txpower(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_rssi(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_iwrange(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCM43XXX_BCMF_DRIVER_H */

View file

@ -2712,6 +2712,13 @@ typedef struct wl_rssi_event
int8_t rssi_levels[MAX_RSSI_LEVELS];
} wl_rssi_event_t;
typedef struct wl_sta_rssi
{
uint32_t rssi;
struct ether_addr sta_addr;
uint16_t foo;
} wl_sta_rssi_t;
#define WLFEATURE_DISABLE_11N 0x00000001
#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002
#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004

View file

@ -915,8 +915,7 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
case SIOCGIWFREQ: /* Get channel/frequency (Hz) */
wlwarn("WARNING: SIOCGIWFREQ not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_channel(priv, (struct iwreq *)arg);
break;
case SIOCSIWMODE: /* Set operation mode */
@ -924,18 +923,15 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
case SIOCGIWMODE: /* Get operation mode */
wlwarn("WARNING: SIOCGIWMODE not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_mode(priv, (struct iwreq *)arg);
break;
case SIOCSIWAP: /* Set access point MAC addresses */
wlwarn("WARNING: SIOCSIWAP not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_set_bssid(priv, (struct iwreq *)arg);
break;
case SIOCGIWAP: /* Get access point MAC addresses */
wlwarn("WARNING: SIOCGIWAP not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_bssid(priv, (struct iwreq *)arg);
break;
case SIOCSIWESSID: /* Set ESSID (network name) */
@ -943,8 +939,7 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
case SIOCGIWESSID: /* Get ESSID */
wlwarn("WARNING: SIOCGIWESSID not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_ssid(priv, (struct iwreq *)arg);
break;
case SIOCSIWRATE: /* Set default bit rate (bps) */
@ -953,8 +948,7 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
case SIOCGIWRATE: /* Get default bit rate (bps) */
wlwarn("WARNING: SIOCGIWRATE not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_rate(priv, (struct iwreq *)arg);
break;
case SIOCSIWTXPOW: /* Set transmit power (dBm) */
@ -963,8 +957,15 @@ static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd,
break;
case SIOCGIWTXPOW: /* Get transmit power (dBm) */
wlwarn("WARNING: SIOCGIWTXPOW not implemented\n");
ret = -ENOSYS;
ret = bcmf_wl_get_txpower(priv, (struct iwreq *)arg);
break;
case SIOCGIWSENS: /* Get transmit power (dBm) */
ret = bcmf_wl_get_rssi(priv, (struct iwreq *)arg);
break;
case SIOCGIWRANGE: /* Get range of parameters */
ret = bcmf_wl_get_iwrange(priv, (struct iwreq *)arg);
break;
default: