return nl80211_new(nls->nlctrl, cmd, flags);
}
-static int nl80211_phy_idx_from_uci_path(struct uci_section *s)
+static const char *nl80211_phy_path_str(const char *phyname)
{
- size_t linklen, pathlen;
- char buf[128], *link;
+ static char path[PATH_MAX];
+ const char *prefix = "/sys/devices/";
+ int prefix_len = strlen(prefix);
+ int buf_len, offset;
struct dirent *e;
- const char *path;
- int idx = -1;
+ char buf[128], *link;
+ int phy_id;
+ int seq = 0;
DIR *d;
- path = uci_lookup_option_string(uci_ctx, s, "path");
- if (!path)
- return -1;
+ if (strncmp(phyname, "phy", 3) != 0)
+ return NULL;
- if ((d = opendir("/sys/class/ieee80211")) != NULL)
- {
- while ((e = readdir(d)) != NULL)
- {
- snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/device", e->d_name);
+ phy_id = atoi(phyname + 3);
+ buf_len = snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/device", phyname);
+ link = realpath(buf, path);
+ if (!link)
+ return NULL;
- link = realpath(buf, NULL);
+ if (strncmp(link, prefix, prefix_len) != 0)
+ return NULL;
- if (link == NULL)
- continue;
+ link += prefix_len;
- linklen = strlen(link);
- pathlen = strlen(path);
+ prefix = "platform/";
+ prefix_len = strlen(prefix);
+ if (!strncmp(link, prefix, prefix_len) && strstr(link, "/pci"))
+ link += prefix_len;
- if (pathlen >= linklen || strcmp(link + (linklen - pathlen), path))
- linklen = 0;
+ snprintf(buf + buf_len, sizeof(buf) - buf_len, "/ieee80211");
+ d = opendir(buf);
+ if (!d)
+ return link;
- free(link);
+ while ((e = readdir(d)) != NULL) {
+ int cur_id;
- if (linklen == 0)
- continue;
+ if (strncmp(e->d_name, "phy", 3) != 0)
+ continue;
- snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", e->d_name);
+ cur_id = atoi(e->d_name + 3);
+ if (cur_id >= phy_id)
+ continue;
- idx = nl80211_readint(buf);
+ seq++;
+ }
- if (idx >= 0)
- break;
- }
+ closedir(d);
- closedir(d);
+ if (!seq)
+ return link;
+
+ offset = link - path + strlen(link);
+ snprintf(path + offset, sizeof(path) - offset, "+%d", seq);
+
+ return link;
+}
+
+static int nl80211_phy_idx_from_uci_path(struct uci_section *s)
+{
+ char buf[128];
+ struct dirent *e;
+ const char *path, *cur_path;
+ int idx = -1;
+ DIR *d;
+
+ path = uci_lookup_option_string(uci_ctx, s, "path");
+ if (!path)
+ return -1;
+
+ d = opendir("/sys/class/ieee80211");
+ if (!d)
+ return -1;
+
+ while ((e = readdir(d)) != NULL) {
+ cur_path = nl80211_phy_path_str(e->d_name);
+ if (!cur_path)
+ continue;
+
+ if (strcmp(cur_path, path) != 0)
+ continue;
+
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", e->d_name);
+ idx = nl80211_readint(buf);
+
+ if (idx >= 0)
+ break;
}
+ closedir(d);
+
return idx;
}
else if (ri[NL80211_RATE_INFO_BITRATE])
re->rate = nla_get_u16(ri[NL80211_RATE_INFO_BITRATE]) * 100;
- if (ri[NL80211_RATE_INFO_VHT_MCS])
+ if (ri[NL80211_RATE_INFO_HE_MCS])
+ {
+ re->is_he = 1;
+ re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_HE_MCS]);
+
+ if (ri[NL80211_RATE_INFO_HE_NSS])
+ re->nss = nla_get_u8(ri[NL80211_RATE_INFO_HE_NSS]);
+ if (ri[NL80211_RATE_INFO_HE_GI])
+ re->he_gi = nla_get_u8(ri[NL80211_RATE_INFO_HE_GI]);
+ if (ri[NL80211_RATE_INFO_HE_DCM])
+ re->he_dcm = nla_get_u8(ri[NL80211_RATE_INFO_HE_DCM]);
+ }
+ else if (ri[NL80211_RATE_INFO_VHT_MCS])
{
re->is_vht = 1;
re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_VHT_MCS]);
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;
+
+ *path = nl80211_phy_path_str(phyname);
+ if (!*path)
+ return -1;
+
+ return 0;
+}
+
const struct iwinfo_ops nl80211_ops = {
.name = "nl80211",
.probe = nl80211_probe,
.countrylist = nl80211_get_countrylist,
.survey = nl80211_get_survey,
.lookup_phy = nl80211_lookup_phyname,
+ .phy_path = nl80211_phy_path,
.close = nl80211_close
};