Commit 794dbaeb authored by Anjan Chanda's avatar Anjan Chanda

libwifi: bcm: fix radio info dump

parent 3df4e224
Pipeline #997 passed with stage
in 51 seconds
......@@ -769,6 +769,7 @@ static int bcm_wifi_bss_info(const char *ifname, struct wifi_bss *bss)
uint32_t bw = 0;
uint8_t *ext_ie, *rrm_ie, *ft_ie;
uint8_t *vht_ie, *ht_ie;
uint8_t *wmm_ie;
uint16_t capability = 0;
uint8_t *ie_start;
uint16_t ie_offset = 0;
......@@ -866,6 +867,14 @@ static int bcm_wifi_bss_info(const char *ifname, struct wifi_bss *bss)
rrm_ie = wifi_find_ie(ie_start, ie_len, 70);
ft_ie = wifi_find_ie(ie_start, ie_len, 55);
wmm_ie = wifi_find_vsie(ie_start, ie_len, (uint8_t *)"\x00\x50\xf2", 2, 0xff);
if (wmm_ie) {
wifi_cap_set(bss->cbitmap, WIFI_CAP_WMM);
wmm_ie += 2 + 3 + 2 + 1; /* skip upto 'version' */
if (!!(wmm_ie[0] & 0x80))
wifi_cap_set(bss->cbitmap, WIFI_CAP_APSD);
}
if (ext_ie) {
bss->caps.valid |= WIFI_CAP_EXT_VALID;
memcpy(bss->caps.ext.byte, &ext_ie[2], min(ext_ie[1], 16));
......@@ -1388,6 +1397,171 @@ static int bcm_acs(const char *ifname, struct acs_param *p)
return strncmp(buf, "Request finished", 16);
}
static int bcm_get_radio_info(const char *name, struct wifi_radio *radio)
{
int ioctl_req_version = 0x2000;
uint8_t basic_idx = 0, supp_idx = 0;
enum wifi_band oper_band = 0;
uint8_t oper_std, supp_std;
uint8_t intbuf[256] = {0};
char alpha2[4] = {0};
wl_bss_info_t *bi;
int beaconint = 0;
int dtimperiod = 0;
int pwr_pcnt = 0;
int srl, lrl;
uint32_t dfs;
int swap = 0;
int nss = 0;
char *tmp;
int ret;
int i;
swap = wl_swap(name);
tmp = calloc(1, WLC_IOCTL_MAXLEN * sizeof(char));
if (tmp == NULL)
return -ENOMEM;
memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version));
if (wl_ioctl(name, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN) < 0) {
free(tmp);
return -1;
}
bi = (wl_bss_info_t *)(tmp + 4);
bi->chanspec = swap ? BCMSWAP16(bi->chanspec) : bi->chanspec;
if (bi->ctl_ch)
radio->channel = bi->ctl_ch;
radio->acs_capable = 1;
radio->acs_enabled = 1; // FIXME
/* oper and supp standards */
if (bcm_get_oper_stds(name, &oper_std) == 0)
radio->oper_std = oper_std;
if (bcm_get_oper_band(name, &oper_band) == 0) {
if (oper_band == BAND_5) {
supp_std = WIFI_A | WIFI_N | WIFI_AC;
radio->dot11h_capable = 1;
} else if (oper_band == BAND_2) {
supp_std = WIFI_B | WIFI_G | WIFI_N;
} else
supp_std = WIFI_UNKNOWN;
radio->supp_std = supp_std;
}
/* basic and supp rates */
bi->rateset.count = swap ? BCMSWAP32(bi->rateset.count) :
bi->rateset.count;
for (i = 0; i < bi->rateset.count; i++) {
if (bi->rateset.rates[i]) {
radio->supp_rates[supp_idx++] =
(bi->rateset.rates[i] & 0x7f) >> 1;
if (!!(bi->rateset.rates[i] & 0x80)) {
radio->basic_rates[basic_idx++] =
(bi->rateset.rates[i] & 0x7f) >> 1;
}
}
}
/* mcs, tx and rx streams */
if (bi->vht_cap) {
uint8_t supp_mcs[2] = {0};
uint16_t vht_rxmap;
int octet = 0;
vht_rxmap = swap ?
BCMSWAP16(bi->vht_rxmcsmap) : bi->vht_rxmcsmap;
*((uint16_t *)supp_mcs) = vht_rxmap;
for (i = 0; i < 16; i += 2) {
uint8_t supp_mcs_mask = 0;
if (i && !(i % 8))
octet++;
supp_mcs_mask = supp_mcs[octet] & (0x3 << (i % 8));
supp_mcs_mask >>= (i % 8);
if (supp_mcs_mask == 3)
break;
nss++;
}
radio->tx_streams = nss;
radio->rx_streams = nss;
radio->aggr_enable = 1;
} else if (bi->n_cap) {
radio->aggr_enable = 1;
for (i = 0; i < MCSSET_LEN; i++) {
if (bi->basic_mcs[i]) {
radio->tx_streams++;
radio->rx_streams++;
}
}
}
/* beaconint, dtimperiod, rts, frag, txpower */
ret = wl_ioctl(name, WLC_GET_BCNPRD, &beaconint, sizeof(int));
if (!ret)
radio->beacon_int = beaconint;
ret = wl_ioctl(name, WLC_GET_DTIMPRD, &dtimperiod, sizeof(int));
if (!ret)
radio->dtim_period = dtimperiod;
ret = wl_iovar_get_noparam(name, "rtsthresh", intbuf, sizeof(intbuf));
if (!ret) {
radio->rts = *((uint16_t *)intbuf);
radio->rts = swap ? BCMSWAP16(radio->rts) : radio->rts;
}
memset(&intbuf, 0, sizeof(intbuf));
ret = wl_iovar_get_noparam(name, "fragthresh", intbuf, sizeof(intbuf));
if (!ret) {
radio->frag = *((uint16_t *)intbuf);
radio->frag = swap ? BCMSWAP16(radio->frag) : radio->frag;
}
ret = wl_ioctl(name, WLC_GET_PWROUT_PERCENTAGE, &pwr_pcnt, sizeof(int));
if (!ret)
radio->txpower = pwr_pcnt;
ret = wl_ioctl(name, WLC_GET_SRL, &srl, sizeof(int));
if (!ret)
radio->srl = srl;
ret = wl_ioctl(name, WLC_GET_LRL, &lrl, sizeof(int));
if (!ret)
radio->lrl = lrl;
/* 11h, country ... */
if (oper_band == BAND_5)
radio->dot11h_capable = 1;
ret = wl_ioctl(name, WLC_GET_SPECT_MANAGMENT, &dfs, sizeof(uint32_t));
if (!ret)
radio->dot11h_enabled = !!(dfs != 0);
ret = bcm_get_country(name, alpha2);
if (!ret)
snprintf(radio->regdomain, 4, "%s", alpha2);
free(tmp);
return 0;
}
static int bcm_disconnect_sta(const char *ifname, uint8_t *sta)
{
char macstr[18] = {0};
......@@ -2780,6 +2954,7 @@ const struct wifi_driver bcm_driver = {
.get_supp_channels = bcm_get_supp_channels,
.get_noise = bcm_get_noise,
.acs = bcm_acs,
.radio.info = bcm_get_radio_info,
.radio.get_stats = bcm_radio_get_stats,
.iface.get_stats = bcm_ap_get_stats,
.iface.get_security = bcm_get_security,
......
......@@ -88,6 +88,36 @@ uint8_t *wifi_find_ie(uint8_t *ies, size_t len, uint8_t eid)
return NULL;
}
uint8_t *wifi_find_vsie(uint8_t *ies, size_t len, uint8_t *oui,
uint8_t type, uint8_t stype)
{
uint8_t *vsie;
uint8_t *end;
if (!ies || !oui || len < 2)
return NULL;
end = ies + len;
while (end - ies > 1) {
if (ies + ies[1] + 2 > end)
return NULL;
vsie = ies;
ies += ies[1] + 2;
if (vsie[0] == 0xdd && !memcmp(&vsie[2], oui, 3)) {
if (type != 0xff && vsie[5] != type)
continue;
if (stype == 0xff || (stype != 0xff && vsie[6] == stype))
return vsie;
}
}
return NULL;
}
void wifi_cap_set_from_ie(uint8_t *bitmap, uint8_t *ie, size_t len)
{
uint8_t eid;
......
......@@ -30,6 +30,10 @@
(e) += 2 + (e)[1])
uint8_t *wifi_find_ie(uint8_t *ies, size_t len, uint8_t eid);
uint8_t *wifi_find_vsie(uint8_t *ies, size_t len, uint8_t *oui, uint8_t type,
uint8_t stype);
void wifi_cap_set_from_ie(uint8_t *caps_bitmap, uint8_t *ie, size_t len);
unsigned long wifi_mcs2rate(uint32_t mcs, uint32_t bw, uint32_t nss, int sgi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment