diff --git a/libwifi/modules/broadcom/wlctrl.c b/libwifi/modules/broadcom/wlctrl.c index 04610d8f7d42ca9c085262b380b5584c4e4575b1..036c3e0fcf01f5e1ddaaceb8e5a881e793c5e434 100644 --- a/libwifi/modules/broadcom/wlctrl.c +++ b/libwifi/modules/broadcom/wlctrl.c @@ -697,7 +697,9 @@ int bcmwl_iface_ap_info(const char *name, struct wifi_ap *ap) ies_len = beacon_len - ((uint8_t *)&bf->cap_info - beacon + 2); beacon_ies = bf->var; - WARN_ON(wifi_oper_stds_set_from_ie(beacon_ies, ies_len, &ap->bss.oper_std)); + ret = wifi_oper_stds_set_from_ie(beacon_ies, ies_len, &ap->bss.oper_std); + if (ret) + WARN_ON(bcmwl_get_oper_stds(name, &ap->bss.oper_std)); WARN_ON(wifi_ssid_advertised_set_from_ie(beacon_ies, ies_len, &ap->ssid_advertised)); WARN_ON(wifi_get_bss_security_from_ies(&ap->bss, beacon_ies, ies_len)); WARN_ON(wifi_apload_set_from_ie(beacon_ies, ies_len, &ap->bss.load)); @@ -775,9 +777,115 @@ int bcmwl_ap_get_oper_stds(const char *name, uint8_t *std) ret = wifi_oper_stds_set_from_ie(beacon_ies, ies_len, std); + if (ret == 0) { + return 0; + } + + ret = bcmwl_get_oper_stds(name, std); + if (WARN_ON(ret)) { return ret; } return 0; } + +int bcmwl_get_oper_band(const char *name, enum wifi_band *band) +{ + uint32_t val, b; + int ret; + struct wl_arg arg = { + .ifname = name, + .cmd = WLC_GET_BAND, + .buf = &val, + .buflen = sizeof(val) + }; + + libwifi_dbg("[%s] %s called (vendor)\n", name, __func__); + + ret = wl_vendor(&arg); + + if (ret) { + libwifi_dbg("[%s] %s fallback to ioctl\n", name, __func__); + ret = wl_ioctl(&arg); + } + + if (ret) { + *band = BAND_UNKNOWN; + return ret; + } + + b = wl_swap_32(name, val); + + switch (b) { + case 1: + *band = BAND_5; + break; + case 2: + *band = BAND_2; + break; + case 0: + *band = BAND_DUAL; + break; + default: + *band = BAND_UNKNOWN; + break; + } + + return ret; +} + +int bcmwl_get_oper_stds(const char *name, uint8_t *std) +{ + int ret; + enum wifi_band band; + uint32_t nmode = 0; + uint32_t vhtmode = 0; + uint32_t he = 0; + + libwifi_dbg("[%s] %s called\n", name, __func__); + + if (!std) + return -EINVAL; + + *std = 0; + + WARN_ON(ret = bcmwl_get_oper_band(name, &band)); + if (ret) + goto exit; + + WARN_ON(ret = wl_iovar_get(name, "nmode", NULL, 0, &nmode, sizeof(nmode))); + if (ret) + goto exit; + + WARN_ON(ret = wl_iovar_get(name, "vhtmode", NULL, 0, &vhtmode, sizeof(vhtmode))); + if (ret) + goto exit;; + + WARN_ON(ret = wl_iovar_get(name, "he", NULL, 0, &he, sizeof(he))); + if (ret) + goto exit; + + if (he) { + *std |= WIFI_AX; + } + + if (vhtmode) { + *std |= WIFI_AC; + } + + if (nmode) { + *std |= WIFI_N; + } + + if (band == BAND_5) { + *std |= WIFI_A; + } + + if (band == BAND_2) { + *std |= WIFI_G; + } + +exit: + return ret; +} diff --git a/libwifi/modules/broadcom/wlctrl.h b/libwifi/modules/broadcom/wlctrl.h index 3ec7754ff075b69d0665055ff033eb29cd143802..7f540758e9b9518ba75a22380fa3dc2947c73326 100644 --- a/libwifi/modules/broadcom/wlctrl.h +++ b/libwifi/modules/broadcom/wlctrl.h @@ -10,5 +10,6 @@ int bcmwl_get_bss_supported_security(const char *name, uint32_t *sec); int bcmwl_iface_get_beacon_ies(const char *name, uint8_t *ies, int *len); int bcmwl_iface_ap_info(const char *name, struct wifi_ap *ap); int bcmwl_ap_get_oper_stds(const char *name, uint8_t *std); +int bcmwl_get_oper_stds(const char *name, uint8_t *std); #endif /* WLCTRL_H */ diff --git a/libwifi/util.c b/libwifi/util.c index e433c67c591695af595c5886901510d3afad28b7..5c7fc86b55845687c2048b8cc617840766331110 100644 --- a/libwifi/util.c +++ b/libwifi/util.c @@ -788,6 +788,8 @@ int wifi_oper_stds_set_from_ie(uint8_t *ies, size_t ies_len, uint8_t *std) if (ds && ds[1] == 1) { channel = ds[2]; + } else { + return -1; } *std = 0;