* Parts of this code are derived from the Linux iw utility.
*/
+#include <sys/stat.h>
#include <limits.h>
#include <glob.h>
#include <fnmatch.h>
return rv;
}
+static int nl80211_get_band(int nla_type)
+{
+ switch (nla_type)
+ {
+ case NL80211_BAND_2GHZ:
+ return IWINFO_BAND_24;
+ case NL80211_BAND_5GHZ:
+ return IWINFO_BAND_5;
+ case NL80211_BAND_6GHZ:
+ return IWINFO_BAND_6;
+ case NL80211_BAND_60GHZ:
+ return IWINFO_BAND_60;
+ }
+
+ return 0;
+}
+
static int nl80211_msg_error(struct sockaddr_nl *nla,
struct nlmsgerr *err, void *arg)
int prefix_len = strlen(prefix);
int buf_len, offset;
struct dirent *e;
- char buf[128], *link;
- int phy_id;
+ char buf[512], *link;
+ int phy_idx;
int seq = 0;
DIR *d;
- if (strncmp(phyname, "phy", 3) != 0)
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", phyname);
+ phy_idx = nl80211_readint(buf);
+ if (phy_idx < 0)
return NULL;
- phy_id = atoi(phyname + 3);
buf_len = snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/device", phyname);
link = realpath(buf, path);
if (!link)
return link;
while ((e = readdir(d)) != NULL) {
- int cur_id;
+ int cur_idx;
- if (strncmp(e->d_name, "phy", 3) != 0)
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", e->d_name);
+ cur_idx = nl80211_readint(buf);
+ if (cur_idx < 0)
continue;
- cur_id = atoi(e->d_name + 3);
- if (cur_id >= phy_id)
+ if (cur_idx >= phy_idx)
continue;
seq++;
static int nl80211_phy_idx_from_path(const char *path)
{
- char buf[128];
+ char buf[512];
struct dirent *e;
const char *cur_path;
int cur_path_len;
if (!opt)
return -1;
- snprintf(buf, sizeof(buf), "/sys/class/ieee80211/*"); /**/
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/*");
if (glob(buf, 0, NULL, &gl))
return -1;
return idx;
}
+static bool nl80211_is_ifname(const char *name)
+{
+ struct stat st;
+ char buffer[PATH_MAX];
+
+ snprintf(buffer, sizeof(buffer), "/sys/class/net/%s", name);
+ return !lstat(buffer, &st);
+}
+
static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname,
int cmd, int flags)
{
- int ifidx = -1, phyidx = -1;
+ unsigned int ifidx = 0;
+ int phyidx = -1;
struct nl80211_msg_conveyor *cv;
if (ifname == NULL)
if (nl80211_init() < 0)
return NULL;
- if (!strncmp(ifname, "phy", 3))
- phyidx = atoi(&ifname[3]);
- else if (!strncmp(ifname, "radio", 5))
- phyidx = nl80211_phy_idx_from_uci(ifname);
-
if (!strncmp(ifname, "mon.", 4))
ifidx = if_nametoindex(&ifname[4]);
- else
+ else if (nl80211_is_ifname(ifname))
ifidx = if_nametoindex(ifname);
+ else
+ {
+ phyidx = nl80211_phy_idx_from_phy(ifname);
+ if (phyidx < 0)
+ phyidx = nl80211_phy_idx_from_uci(ifname);
+ }
/* Valid ifidx must be greater than 0 */
if ((ifidx <= 0) && (phyidx < 0))
#define nl80211_wait(family, group, ...) \
__nl80211_wait(family, group, __VA_ARGS__, 0)
-
+/* This is linux's ieee80211_freq_khz_to_channel() which is:
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018-2022 Intel Corporation
+ */
static int nl80211_freq2channel(int freq)
{
if (freq == 2484)
return (freq - 2407) / 5;
else if (freq >= 4910 && freq <= 4980)
return (freq - 4000) / 5;
- else if(freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6)
+ else if (freq < 5925)
+ return (freq - 5000) / 5;
+ else if (freq == 5935)
+ return 2;
+ else if (freq <= 45000) /* DMG band lower limit */
+ /* see 802.11ax D6.1 27.3.22.2 */
+ return (freq - 5950) / 5;
+ else if (freq >= 58320 && freq <= 70200)
return (freq - 56160) / 2160;
else
- return (freq - 5000) / 5;
+ return 0;
}
-static int nl80211_channel2freq(int channel, const char *band)
+/* This is linux's ieee80211_channel_to_freq_khz() which is:
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018-2022 Intel Corporation
+ */
+static int nl80211_channel2freq(int channel, const char *band, bool ax)
{
+ if (channel < 1)
+ return 0;
+
if (!band || band[0] != 'a')
{
if (channel == 14)
else if (channel < 14)
return (channel * 5) + 2407;
}
- else if ( strcmp(band, "ad") == 0)
+ else if (strcmp(band, "ad") == 0)
{
- return 56160 + 2160 * channel;
+ if (channel < 7)
+ return 56160 + 2160 * channel;
+ }
+ else if (ax)
+ {
+ if (channel == 2)
+ return 5935;
+ if (channel < 233)
+ return (channel * 5) + 5950;
}
else
{
return 0;
}
-static int nl80211_ifname2phy_cb(struct nl_msg *msg, void *arg)
+static uint8_t nl80211_freq2band(int freq)
+{
+ if (freq >= 2412 && freq <= 2484)
+ return IWINFO_BAND_24;
+ else if (freq >= 5160 && freq <= 5885)
+ return IWINFO_BAND_5;
+ else if (freq >= 5925 && freq <= 7125)
+ return IWINFO_BAND_6;
+ else if (freq >= 58320 && freq <= 69120)
+ return IWINFO_BAND_60;
+
+ return 0;
+}
+
+static int nl80211_phyname_cb(struct nl_msg *msg, void *arg)
{
char *buf = arg;
struct nlattr **attr = nl80211_parse(msg);
memset(phy, 0, sizeof(phy));
nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
- nl80211_ifname2phy_cb, phy);
+ nl80211_phyname_cb, phy);
+
+ return phy[0] ? phy : NULL;
+}
+
+static char * nl80211_phyidx2name(unsigned int idx)
+{
+ struct nl80211_msg_conveyor *cv;
+ static char phy[32] = { 0 };
+
+ if (nl80211_init() < 0)
+ return NULL;
+
+ cv = nl80211_new(nls->nl80211, NL80211_CMD_GET_WIPHY, 0);
+ if (!cv)
+ return NULL;
+
+ NLA_PUT_U32(cv->msg, NL80211_ATTR_WIPHY, idx);
+
+ memset(phy, 0, sizeof(phy));
+ nl80211_send(cv, nl80211_phyname_cb, phy);
return phy[0] ? phy : NULL;
+
+nla_put_failure:
+ return NULL;
}
static char * nl80211_phy2ifname(const char *ifname)
{
- int ifidx = -1, cifidx = -1, phyidx = -1;
- char buffer[64];
+ int ifidx = -1, cifidx, lmode = 1, clmode, phyidx;
+ char buffer[512];
static char nif[IFNAMSIZ] = { 0 };
-
DIR *d;
struct dirent *e;
- /* Only accept phy name of the form phy%d or radio%d */
+ /* Only accept phy name in the form of phy%d or radio%d */
if (!ifname)
return NULL;
- else if (!strncmp(ifname, "phy", 3))
- phyidx = atoi(&ifname[3]);
- else if (!strncmp(ifname, "radio", 5))
- phyidx = nl80211_phy_idx_from_uci(ifname);
- else
+
+ phyidx = nl80211_phy_idx_from_phy(ifname);
+ if (phyidx < 0)
+ phyidx = nl80211_phy_idx_from_uci(ifname);;
+ if (phyidx < 0)
return NULL;
memset(nif, 0, sizeof(nif));
- if (phyidx > -1)
+ if ((d = opendir("/sys/class/net")) != NULL)
{
- if ((d = opendir("/sys/class/net")) != NULL)
+ while ((e = readdir(d)) != NULL)
{
- while ((e = readdir(d)) != NULL)
- {
- snprintf(buffer, sizeof(buffer),
- "/sys/class/net/%s/phy80211/index", e->d_name);
+ snprintf(buffer, sizeof(buffer),
+ "/sys/class/net/%s/phy80211/index", e->d_name);
+ if (nl80211_readint(buffer) != phyidx)
+ continue;
- if (nl80211_readint(buffer) == phyidx)
- {
- snprintf(buffer, sizeof(buffer),
- "/sys/class/net/%s/ifindex", e->d_name);
+ snprintf(buffer, sizeof(buffer),
+ "/sys/class/net/%s/ifindex", e->d_name);
+ cifidx = nl80211_readint(buffer);
- if ((cifidx = nl80211_readint(buffer)) >= 0 &&
- ((ifidx < 0) || (cifidx < ifidx)))
- {
- ifidx = cifidx;
- strncpy(nif, e->d_name, sizeof(nif) - 1);
- }
- }
- }
+ if (cifidx < 0)
+ continue;
- closedir(d);
+ snprintf(buffer, sizeof(buffer),
+ "/sys/class/net/%s/link_mode", e->d_name);
+ clmode = nl80211_readint(buffer);
+
+ /* prefer non-supplicant-based devices */
+ if ((ifidx < 0) || (cifidx < ifidx) || ((lmode == 1) && (clmode != 1)))
+ {
+ ifidx = cifidx;
+ lmode = clmode;
+ strncpy(nif, e->d_name, sizeof(nif) - 1);
+ }
}
+
+ closedir(d);
}
return nif[0] ? nif : NULL;
IWINFO_OPMODE_CLIENT, /* managed */
IWINFO_OPMODE_MASTER, /* AP */
IWINFO_OPMODE_AP_VLAN, /* AP/VLAN */
- IWINFO_OPMODE_WDS, /* WDS */
+ IWINFO_OPMODE_WDS, /* WDS */
IWINFO_OPMODE_MONITOR, /* monitor */
IWINFO_OPMODE_MESHPOINT, /* mesh point */
IWINFO_OPMODE_P2P_CLIENT, /* P2P-client */
remote.sun_family = AF_UNIX;
remote_length = sizeof(remote.sun_family) +
- sprintf(remote.sun_path, "/var/run/wpa_supplicant-%s/%s",
- ifname, ifname);
+ sprintf(remote.sun_path, "/var/run/wpa_supplicant/%s", ifname);
+
+ /* Set client socket file permissions so that bind() creates the client
+ * socket with these permissions and there is no need to try to change
+ * them with chmod() after bind() which would have potential issues with
+ * race conditions. These permissions are needed to make sure the server
+ * side (wpa_supplicant or hostapd) can reply to the control interface
+ * messages.
+ *
+ * The lchown() calls below after bind() are also part of the needed
+ * operations to allow the response to go through. Those are using the
+ * no-deference-symlinks version to avoid races. */
+ fchmod(sock, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0)
{
if (connect(sock, (struct sockaddr *)&remote, remote_length))
{
- remote_length = sizeof(remote.sun_family) +
- sprintf(remote.sun_path, "/var/run/wpa_supplicant/%s", ifname);
-
- if (connect(sock, (struct sockaddr *)&remote, remote_length))
- {
- close(sock);
- return -1;
- }
+ close(sock);
+ return -1;
}
local->sun_family = AF_UNIX;
return -1;
}
+ /* Set group even if we do not have privileges to change owner */
+ lchown(local->sun_path, -1, 101);
+ lchown(local->sun_path, 101, 101);
+
return sock;
}
static void nl80211_ifdel(const char *ifname)
{
struct nl80211_msg_conveyor *req;
- int err;
req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0);
if (req)
struct nlattr **tb = nl80211_parse(msg);
struct nlattr *bss[NL80211_BSS_MAX + 1];
- static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
[NL80211_BSS_INFORMATION_ELEMENTS] = { 0 },
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
};
/* failed, try to obtain Mesh ID */
if (sb.ssid[0] == 0)
iwinfo_ubus_query(res ? res : ifname, "mesh_id",
- sb.ssid, IWINFO_ESSID_MAX_SIZE + 1);
+ buf, IWINFO_ESSID_MAX_SIZE + 1);
return (sb.ssid[0] == 0) ? -1 : 0;
}
struct nlattr **attr = nl80211_parse(msg);
struct nlattr *binfo[NL80211_BSS_MAX + 1];
- static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
};
static int nl80211_get_frequency(const char *ifname, int *buf)
{
- char *res, channel[4], hwmode[3];
+ char *res, channel[4] = { 0 }, hwmode[3] = { 0 }, ax[2] = { 0 };
/* try to find frequency from interface info */
res = nl80211_phy2ifname(ifname);
/* failed, try to find frequency from hostapd info */
if ((*buf == 0) &&
nl80211_hostapd_query(ifname, "hw_mode", hwmode, sizeof(hwmode),
- "channel", channel, sizeof(channel)) == 2)
+ "channel", channel, sizeof(channel),
+ "ieee80211ax", ax, sizeof(ax)) >= 2)
{
- *buf = nl80211_channel2freq(atoi(channel), hwmode);
+ *buf = nl80211_channel2freq(atoi(channel), hwmode, ax[0] == '1');
}
/* failed, try to find frequency from scan results */
struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
- static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ static const struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
};
- static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+ static const struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
struct nlattr **tb = nl80211_parse(msg);
struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
- static struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = {
+ static const struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = {
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
};
return 0;
}
-static struct {
+static const struct {
const char *match;
int version;
int suite;
{ "IEEE 802.1X/EAP", 0, IWINFO_KMGMT_8021x },
{ "EAP-SUITE-B-192", 4, IWINFO_KMGMT_8021x },
{ "EAP-SUITE-B", 4, IWINFO_KMGMT_8021x },
+ { "EAP-SHA384", 4, IWINFO_KMGMT_8021x },
{ "EAP-SHA256", 0, IWINFO_KMGMT_8021x },
{ "PSK-SHA256", 0, IWINFO_KMGMT_PSK },
{ "NONE", 0, IWINFO_KMGMT_NONE },
}
}
-static struct {
+static const struct {
const char *match;
int cipher;
} wpa_cipher_strings[] = {
- { "WEP-104", IWINFO_CIPHER_WEP104 },
- { "WEP-40", IWINFO_CIPHER_WEP40 },
- { "NONE", IWINFO_CIPHER_NONE },
- { "TKIP", IWINFO_CIPHER_TKIP },
- { "CCMP", IWINFO_CIPHER_CCMP },
- { "GCMP", IWINFO_CIPHER_GCMP }
+ { "WEP-104", IWINFO_CIPHER_WEP104 },
+ { "WEP-40", IWINFO_CIPHER_WEP40 },
+ { "NONE", IWINFO_CIPHER_NONE },
+ { "TKIP", IWINFO_CIPHER_TKIP },
+ { "CCMP-256",IWINFO_CIPHER_CCMP256 },
+ { "CCMP", IWINFO_CIPHER_CCMP },
+ { "GCMP-256",IWINFO_CIPHER_GCMP256 },
+ { "GCMP", IWINFO_CIPHER_GCMP }
};
static void parse_wpa_ciphers(const char *str, uint16_t *ciphers)
if (!strncmp(p, "WPA-", 4))
p += 4;
+ if (!strncmp(p, "FT-", 3))
+ p += 3;
+
parse_wpa_suites(p, atoi(wpa), &c->wpa_version, &c->auth_suites);
}
else if (ri[NL80211_RATE_INFO_BITRATE])
re->rate = nla_get_u16(ri[NL80211_RATE_INFO_BITRATE]) * 100;
- if (ri[NL80211_RATE_INFO_HE_MCS])
+ if (ri[NL80211_RATE_INFO_EHT_MCS])
+ {
+ re->is_eht = 1;
+ re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_EHT_MCS]);
+
+ if (ri[NL80211_RATE_INFO_EHT_NSS])
+ re->nss = nla_get_u8(ri[NL80211_RATE_INFO_EHT_NSS]);
+ if (ri[NL80211_RATE_INFO_EHT_GI])
+ re->eht_gi = nla_get_u8(ri[NL80211_RATE_INFO_EHT_GI]);
+ }
+ else if (ri[NL80211_RATE_INFO_HE_MCS])
{
re->is_he = 1;
re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_HE_MCS]);
else if (ri[NL80211_RATE_INFO_80P80_MHZ_WIDTH] ||
ri[NL80211_RATE_INFO_160_MHZ_WIDTH])
re->mhz = 160;
+ else if (ri[NL80211_RATE_INFO_320_MHZ_WIDTH])
+ re->mhz_hi = 320 / 256, re->mhz = 320 % 256;
else
re->mhz = 20;
struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
int rc;
- static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ static const struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
[NL80211_SURVEY_INFO_TIME] = { .type = NLA_U64 },
struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
struct nl80211_sta_flag_update *sta_flags;
- static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ static const struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
[NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
[NL80211_STA_INFO_CONNECTED_TIME]= { .type = NLA_U32 },
[NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32 },
};
- static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+ static const struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
nl80211_parse_rateinfo(rinfo, &e->tx_rate);
- if (sinfo[NL80211_STA_INFO_RX_BYTES])
+ if (sinfo[NL80211_STA_INFO_RX_BYTES64])
+ e->rx_bytes = nla_get_u64(sinfo[NL80211_STA_INFO_RX_BYTES64]);
+ else if (sinfo[NL80211_STA_INFO_RX_BYTES])
e->rx_bytes = nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
- if (sinfo[NL80211_STA_INFO_TX_BYTES])
+ if (sinfo[NL80211_STA_INFO_TX_BYTES64])
+ e->tx_bytes = nla_get_u64(sinfo[NL80211_STA_INFO_TX_BYTES64]);
+ else if (sinfo[NL80211_STA_INFO_TX_BYTES])
e->tx_bytes = nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]);
if (sinfo[NL80211_STA_INFO_TX_RETRIES])
struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
struct nlattr *band, *freq;
- static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ static const struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
{
int err, ch_cur;
int dbm_max = -1, dbm_cur, dbm_cnt;
- struct nl80211_msg_conveyor *req;
struct iwinfo_txpwrlist_entry entry;
if (nl80211_get_channel(ifname, &ch_cur))
iwinfo_parse_rsn(&e->crypto, ie + 6, ie[1] - 4,
IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK);
break;
- case 61: /* HT oeration */
+ case 61: /* HT operation */
if (ie[1] >= 3) {
e->ht_chan_info.primary_chan = ie[2];
e->ht_chan_info.secondary_chan_off = ie[3] & 0x3;
struct nlattr **tb = nl80211_parse(msg);
struct nlattr *bss[NL80211_BSS_MAX + 1];
- static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
[NL80211_BSS_TSF] = { .type = NLA_U64 },
[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
[NL80211_BSS_BSSID] = { 0 },
sl->e->crypto.enabled = 1;
if (bss[NL80211_BSS_FREQUENCY])
- sl->e->channel = nl80211_freq2channel(nla_get_u32(
- bss[NL80211_BSS_FREQUENCY]));
+ {
+ sl->e->mhz = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ sl->e->band = nl80211_freq2band(sl->e->mhz);
+ sl->e->channel = nl80211_freq2channel(sl->e->mhz);
+ }
if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
nl80211_get_scanlist_ie(bss, sl->e);
e->mode = IWINFO_OPMODE_MASTER;
/* Channel */
- e->channel = nl80211_freq2channel(atoi(freq));
+ e->mhz = atoi(freq);
+ e->band = nl80211_freq2band(e->mhz);
+ e->channel = nl80211_freq2channel(e->mhz);
/* Signal */
rssi = atoi(signal);
iwinfo_ifup(ifname);
nl80211_hostapd_hup(ifname);
}
+ else
+ rv = -1;
nl80211_ifdel(res);
return rv;
freqs[NL80211_FREQUENCY_ATTR_DISABLED])
continue;
+ e->band = nl80211_get_band(band->nla_type);
e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
e->channel = nl80211_freq2channel(e->mhz);
- e->restricted = (
- freqs[NL80211_FREQUENCY_ATTR_NO_IR] &&
- !freqs[NL80211_FREQUENCY_ATTR_RADAR]
- ) ? 1 : 0;
-
if (freqs[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
e->flags |= IWINFO_FREQ_NO_HT40MINUS;
if (freqs[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
e->flags |= IWINFO_FREQ_NO_20MHZ;
if (freqs[NL80211_FREQUENCY_ATTR_NO_10MHZ])
e->flags |= IWINFO_FREQ_NO_10MHZ;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_HE])
+ e->flags |= IWINFO_FREQ_NO_HE;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_IR] &&
+ !freqs[NL80211_FREQUENCY_ATTR_RADAR])
+ e->flags |= IWINFO_FREQ_NO_IR;
+ if (freqs[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
+ e->flags |= IWINFO_FREQ_INDOOR_ONLY;
+
+ /* keep backwards compatibility */
+ e->restricted = (e->flags & IWINFO_FREQ_NO_IR) ? 1 : 0;
e++;
arr->count++;
uint16_t nl_ht;
uint32_t nl_vht;
uint16_t he_phy_cap[6];
+ uint16_t eht_phy_cap[9];
};
-static int nl80211_eval_modelist(struct nl80211_modes *m)
+static void nl80211_eval_modelist(struct nl80211_modes *m)
{
/* Treat any nonzero capability as 11n */
if (m->nl_ht > 0)
m->ht |= IWINFO_HTMODE_HE160 | IWINFO_HTMODE_HE80_80;
}
+ if (m->eht_phy_cap[0] != 0) {
+ m->hw |= IWINFO_80211_BE;
+ m->ht |= IWINFO_HTMODE_EHT20;
+
+ if (m->he_phy_cap[0] & BIT(9))
+ m->ht |= IWINFO_HTMODE_EHT40;
+ if (m->he_phy_cap[0] & BIT(10))
+ m->ht |= IWINFO_HTMODE_EHT40 | IWINFO_HTMODE_EHT80;
+ if (m->he_phy_cap[0] & BIT(11))
+ m->ht |= IWINFO_HTMODE_EHT160;
+ if (m->he_phy_cap[0] & BIT(12))
+ m->ht |= IWINFO_HTMODE_EHT160 | IWINFO_HTMODE_EHT80_80;
+ if ((m->eht_phy_cap[0] & BIT(9)) && (m->bands & IWINFO_BAND_6))
+ m->ht |= IWINFO_HTMODE_EHT320;
+ }
+
if (m->bands & IWINFO_BAND_24)
{
m->hw |= IWINFO_80211_B;
m->hw |= IWINFO_80211_G;
}
- if (m->nl_vht)
+ if (m->bands & IWINFO_BAND_5)
{
/* Treat any nonzero capability as 11ac */
if (m->nl_vht > 0)
m->ht |= IWINFO_HTMODE_VHT160;
}
}
+ else
+ {
+ m->hw |= IWINFO_80211_A;
+ }
}
if (m->bands & IWINFO_BAND_60)
m->hw |= IWINFO_80211_AD;
}
- if (!(m->hw & IWINFO_80211_AC))
- {
- m->hw |= IWINFO_80211_A;
- }
}
static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
{
struct nl80211_modes *m = arg;
- int bands_remain, freqs_remain;
- uint16_t caps = 0;
- uint32_t vht_caps = 0;
+ int bands_remain;
struct nlattr **attr = nl80211_parse(msg);
struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
- struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
- struct nlattr *band, *freq;
- uint32_t freq_mhz;
+ struct nlattr *band;
if (attr[NL80211_ATTR_WIPHY_BANDS])
{
nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
{
+ m->bands |= nl80211_get_band(band->nla_type);
+
nla_parse(bands, NL80211_BAND_ATTR_MAX,
nla_data(band), nla_len(band), NULL);
nla_for_each_nested(nl_iftype, bands[NL80211_BAND_ATTR_IFTYPE_DATA], rem_band) {
nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
nla_data(nl_iftype), nla_len(nl_iftype), NULL);
+
+ // HE
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
len);
}
- }
- }
-
- if (bands[NL80211_BAND_ATTR_FREQS]) {
- nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
- freqs_remain)
- {
- nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(freq), nla_len(freq), NULL);
-
- if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
- freq_mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
+ // EHT
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]);
- if (freq_mhz > 2400 && freq_mhz < 2485)
- {
- m->bands |= IWINFO_BAND_24;
- }
- else if (freq_mhz > 5000 && freq_mhz < 5850)
- {
- m->bands |= IWINFO_BAND_5;
- }
- else if (freq_mhz > 6000 && freq_mhz < 7120)
- {
- m->bands |= IWINFO_BAND_6;
- }
- else if (freq_mhz >= 56160)
- {
- m->bands |= IWINFO_BAND_60;
+ if (len > sizeof(m->eht_phy_cap) - 1)
+ len = sizeof(m->eht_phy_cap) - 1;
+ memcpy(&((uint8_t *)m->eht_phy_cap)[1],
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]),
+ len);
}
}
}
static int nl80211_get_htmode(const char *ifname, int *buf)
{
- struct chan_info chn = { .width = 0, .mode = 0 };
- char *res;
+ struct chan_info chn = { 0 };
+ char *res, b[2] = { 0 };
int err;
+ bool he = false;
+ bool eht = false;
res = nl80211_phy2ifname(ifname);
*buf = 0;
if (err)
return -1;
+ if (nl80211_hostapd_query(res ? res : ifname, "ieee80211be", b, sizeof(b)))
+ eht = b[0] == '1';
+
+ if (nl80211_hostapd_query(res ? res : ifname, "ieee80211ax", b, sizeof(b)))
+ he = b[0] == '1';
+ else if (nl80211_wpactl_query(res ? res : ifname, "wifi_generation", b, sizeof(b)))
+ he = b[0] == '6';
+
switch (chn.width) {
case NL80211_CHAN_WIDTH_20:
- if (chn.mode == -1)
+ if (he)
+ *buf = (eht == true) ? IWINFO_HTMODE_EHT20 : IWINFO_HTMODE_HE20;
+ else if (chn.mode == -1)
*buf = IWINFO_HTMODE_VHT20;
else
*buf = IWINFO_HTMODE_HT20;
break;
case NL80211_CHAN_WIDTH_40:
- if (chn.mode == -1)
+ if (he)
+ *buf = (eht == true) ? IWINFO_HTMODE_EHT40 : IWINFO_HTMODE_HE40;
+ else if (chn.mode == -1)
*buf = IWINFO_HTMODE_VHT40;
else
*buf = IWINFO_HTMODE_HT40;
break;
case NL80211_CHAN_WIDTH_80:
- *buf = IWINFO_HTMODE_VHT80;
+ if (he)
+ *buf = (eht == true) ? IWINFO_HTMODE_EHT80 : IWINFO_HTMODE_HE80;
+ else
+ *buf = IWINFO_HTMODE_VHT80;
break;
case NL80211_CHAN_WIDTH_80P80:
- *buf = IWINFO_HTMODE_VHT80_80;
+ if (he)
+ *buf = (eht == true) ? IWINFO_HTMODE_EHT80_80 : IWINFO_HTMODE_HE80_80;
+ else
+ *buf = IWINFO_HTMODE_VHT80_80;
break;
case NL80211_CHAN_WIDTH_160:
- *buf = IWINFO_HTMODE_VHT160;
+ if (he)
+ *buf = (eht == true) ? IWINFO_HTMODE_EHT160 : IWINFO_HTMODE_HE160;
+ else
+ *buf = IWINFO_HTMODE_VHT160;
+ break;
+ case NL80211_CHAN_WIDTH_320:
+ *buf = IWINFO_HTMODE_EHT320;
break;
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
nla_for_each_nested(comb, attr[NL80211_ATTR_INTERFACE_COMBINATIONS], comb_rem)
{
- static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+ static const struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
};
struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB+1];
- static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+ static const struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
};
static int nl80211_hardware_id_from_fdt(struct iwinfo_hardware_id *id, const char *ifname)
{
- char *phy, compat[64], path[PATH_MAX];
- int i;
+ char *phy, path[PATH_MAX];
/* Try to determine the phy name from the given interface */
phy = nl80211_ifname2phy(ifname);
snprintf(path, sizeof(path), "/sys/class/%s/%s/device/of_node/compatible",
phy ? "ieee80211" : "net", phy ? phy : ifname);
- if (nl80211_readstr(path, compat, sizeof(compat)) <= 0)
+ if (nl80211_readstr(path, id->compatible, sizeof(id->compatible)) <= 0)
return -1;
- if (!strcmp(compat, "qca,ar9130-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0029;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9130;
- } else if (!strcmp(compat, "qca,ar9330-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0030;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9330;
- } else if (!strcmp(compat, "qca,ar9340-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0030;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9340;
- } else if (!strcmp(compat, "qca,qca9530-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0033;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9530;
- } else if (!strcmp(compat, "qca,qca9550-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0033;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9550;
- } else if (!strcmp(compat, "qca,qca9560-wmac")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x0033;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x9560;
- } else if (!strcmp(compat, "qcom,ipq4019-wifi")) {
- id->vendor_id = 0x168c;
- id->device_id = 0x003c;
- id->subsystem_vendor_id = 0x168c;
- id->subsystem_device_id = 0x4019;
- } else if (!strcmp(compat, "mediatek,mt7622-wmac")) {
- id->vendor_id = 0x14c3;
- id->device_id = 0x7622;
- id->subsystem_vendor_id = 0x14c3;
- id->subsystem_device_id = 0x7622;
- }
- return (id->vendor_id && id->device_id) ? 0 : -1;
+ return 0;
}
{ "vendor", &id->vendor_id },
{ "device", &id->device_id },
{ "subsystem_vendor", &id->subsystem_vendor_id },
- { "subsystem_device", &id->subsystem_device_id }
+ { "subsystem_device", &id->subsystem_device_id },
+ { "../idVendor", &id->subsystem_vendor_id },
+ { "../idProduct", &id->subsystem_device_id }
};
memset(id, 0, sizeof(*id));
*lookup[i].dest = strtoul(num, NULL, 16);
}
- /* Failed to obtain hardware IDs, try FDT */
- if (id->vendor_id == 0 || id->device_id == 0)
- if (!nl80211_hardware_id_from_fdt(id, ifname))
- return 0;
-
- /* Failed to obtain hardware IDs, search board config */
- if (id->vendor_id == 0 || id->device_id == 0)
- return iwinfo_hardware_id_from_mtd(id);
+ /* Failed to obtain hardware PCI/USB IDs... */
+ if (id->vendor_id == 0 && id->device_id == 0 &&
+ id->subsystem_vendor_id == 0 && id->subsystem_device_id == 0)
+ /* ... first fallback to FDT ... */
+ if (nl80211_hardware_id_from_fdt(id, ifname) == -1)
+ /* ... then board config */
+ return iwinfo_hardware_id_from_mtd(id);
return 0;
}
static int nl80211_lookup_phyname(const char *section, char *buf)
{
+ const char *name;
int idx;
if (!strncmp(section, "path=", 5))
if (idx < 0)
return -1;
- sprintf(buf, "phy%d", idx);
+ name = nl80211_phyidx2name(idx);
+ if (!name)
+ return -1;
+
+ strcpy(buf, name);
return 0;
}
static int nl80211_phy_path(const char *phyname, const char **path)
{
- if (strncmp(phyname, "phy", 3) != 0)
- return -1;
-
if (strchr(phyname, '/'))
return -1;