diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c index ba97bb5733f..c477cfc7a7a 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.c @@ -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; +} diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h index 4386e4624e2..3a5c96d63e1 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_driver.h @@ -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 */ diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h b/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h index d57b463598d..959fb294c03 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_ioctl.h @@ -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 diff --git a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c index 1a87db2c47f..acae29d4923 100644 --- a/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c +++ b/drivers/wireless/ieee80211/bcm43xxx/bcmf_netdev.c @@ -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: