* 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)
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)
{
if (!strncmp(ifname, "mon.", 4))
ifidx = if_nametoindex(&ifname[4]);
- else
+ else if (nl80211_is_ifname(ifname))
ifidx = if_nametoindex(ifname);
-
- if (!ifidx) {
+ else
+ {
phyidx = nl80211_phy_idx_from_phy(ifname);
if (phyidx < 0)
phyidx = nl80211_phy_idx_from_uci(ifname);
#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)
+ {
+ if (channel < 7)
+ return 56160 + 2160 * channel;
+ }
+ else if (ax)
{
- return 56160 + 2160 * channel;
+ if (channel == 2)
+ return 5935;
+ if (channel < 233)
+ return (channel * 5) + 5950;
}
else
{
return 0;
}
+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;
static char * nl80211_phy2ifname(const char *ifname)
{
- int ifidx = -1, cifidx = -1, phyidx = -1;
+ 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;
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
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;
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 },
};
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;
}
}
-static struct {
+static const struct {
const char *match;
int cipher;
} wpa_cipher_strings[] = {
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 },
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);
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++;
static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
{
struct nl80211_modes *m = arg;
- int bands_remain, freqs_remain;
+ 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);
}
}
}
-
- 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]);
-
- 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;
- }
- }
- }
}
m->ok = 1;
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;
res = nl80211_phy2ifname(ifname);
*buf = 0;
if (err)
return -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 = 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 = 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 = IWINFO_HTMODE_HE80;
+ else
+ *buf = IWINFO_HTMODE_VHT80;
break;
case NL80211_CHAN_WIDTH_80P80:
- *buf = IWINFO_HTMODE_VHT80_80;
+ if (he)
+ *buf = IWINFO_HTMODE_HE80_80;
+ else
+ *buf = IWINFO_HTMODE_VHT80_80;
break;
case NL80211_CHAN_WIDTH_160:
- *buf = IWINFO_HTMODE_VHT160;
+ if (he)
+ *buf = IWINFO_HTMODE_HE160;
+ else
+ *buf = IWINFO_HTMODE_VHT160;
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];
+ 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;
- } else if (!strcmp(compat, "mediatek,mt7986-wmac")) {
- id->vendor_id = 0x14c3;
- id->device_id = 0x7986;
- id->subsystem_vendor_id = 0x14c3;
- id->subsystem_device_id = 0x7986;
- }
-
- 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;
}