return &cv;
err:
- if (cb)
- nl_cb_put(cb);
-
if (req)
nlmsg_free(req);
snprintf(buf, sizeof(buf), "/sys/devices/%s/ieee80211/*/index", opt); /**/
if (glob(buf, 0, NULL, &gl))
+ snprintf(buf, sizeof(buf), "/sys/devices/platform/%s/ieee80211/*/index", opt); /**/
+
+ if (glob(buf, 0, NULL, &gl))
return -1;
if (gl.gl_pathc > 0)
return NULL;
}
-static struct nl80211_msg_conveyor * nl80211_send(
- struct nl80211_msg_conveyor *cv,
- int (*cb_func)(struct nl_msg *, void *), void *cb_arg
-) {
+static int nl80211_send(struct nl80211_msg_conveyor *cv,
+ int (*cb_func)(struct nl_msg *, void *),
+ void *cb_arg)
+{
static struct nl80211_msg_conveyor rcv;
- int err = 1;
+ int err;
if (cb_func)
nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, cb_func, cb_arg);
else
nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_msg_response, &rcv);
- if (nl_send_auto_complete(nls->nl_sock, cv->msg) < 0)
- goto err;
+ err = nl_send_auto_complete(nls->nl_sock, cv->msg);
+
+ if (err < 0)
+ goto out;
+
+ err = 1;
nl_cb_err(cv->cb, NL_CB_CUSTOM, nl80211_msg_error, &err);
nl_cb_set(cv->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_msg_finish, &err);
while (err > 0)
nl_recvmsgs(nls->nl_sock, cv->cb);
- return &rcv;
+out:
+ nl80211_free(cv);
+ return err;
+}
-err:
- nl_cb_put(cv->cb);
- nlmsg_free(cv->msg);
+static int nl80211_request(const char *ifname, int cmd, int flags,
+ int (*cb_func)(struct nl_msg *, void *),
+ void *cb_arg)
+{
+ struct nl80211_msg_conveyor *cv;
- return NULL;
+ cv = nl80211_msg(ifname, cmd, flags);
+
+ if (!cv)
+ return -ENOMEM;
+
+ return nl80211_send(cv, cb_func, cb_arg);
}
static struct nlattr ** nl80211_parse(struct nl_msg *msg)
return attr;
}
+static int nl80211_get_protocol_features_cb(struct nl_msg *msg, void *arg)
+{
+ uint32_t *features = arg;
+ struct nlattr **attr = nl80211_parse(msg);
+
+ if (attr[NL80211_ATTR_PROTOCOL_FEATURES])
+ *features = nla_get_u32(attr[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+static int nl80211_get_protocol_features(const char *ifname)
+{
+ struct nl80211_msg_conveyor *req;
+ uint32_t features = 0;
+
+ req = nl80211_msg(ifname, NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
+ if (req) {
+ nl80211_send(req, nl80211_get_protocol_features_cb, &features);
+ nl80211_free(req);
+ }
+
+ return features;
+}
static int nl80211_subscribe_cb(struct nl_msg *msg, void *arg)
{
{
struct nl80211_group_conveyor cv = { .name = group, .id = -ENOENT };
struct nl80211_msg_conveyor *req;
+ int err;
req = nl80211_ctl(CTRL_CMD_GETFAMILY, 0);
if (req)
{
NLA_PUT_STRING(req->msg, CTRL_ATTR_FAMILY_NAME, family);
- nl80211_send(req, nl80211_subscribe_cb, &cv);
+ err = nl80211_send(req, nl80211_subscribe_cb, &cv);
+
+ if (err)
+ return err;
+
+ return nl_socket_add_membership(nls->nl_sock, cv.id);
nla_put_failure:
nl80211_free(req);
}
- return nl_socket_add_membership(nls->nl_sock, cv.id);
+ return -ENOMEM;
}
struct nl80211_event_conveyor *cv = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- if (gnlh->cmd == cv->wait)
+ if (cv->wait[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))
cv->recv = gnlh->cmd;
return NL_SKIP;
return NL_OK;
}
-static int nl80211_wait(const char *family, const char *group, int cmd)
+static int __nl80211_wait(const char *family, const char *group, ...)
{
- struct nl80211_event_conveyor cv = { .wait = cmd };
+ struct nl80211_event_conveyor cv = { };
struct nl_cb *cb;
+ int err = 0;
+ int cmd;
+ va_list ap;
if (nl80211_subscribe(family, group))
return -ENOENT;
if (!cb)
return -ENOMEM;
+ nl_cb_err(cb, NL_CB_CUSTOM, nl80211_msg_error, &err);
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_wait_seq_check, NULL);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wait_cb, &cv );
- while (!cv.recv)
+ va_start(ap, group);
+
+ for (cmd = va_arg(ap, int); cmd != 0; cmd = va_arg(ap, int))
+ cv.wait[cmd / 32] |= (1 << (cmd % 32));
+
+ va_end(ap);
+
+ while (!cv.recv && !err)
nl_recvmsgs(nls->nl_sock, cb);
nl_cb_put(cb);
- return 0;
+ return err;
}
+#define nl80211_wait(family, group, ...) \
+ __nl80211_wait(family, group, __VA_ARGS__, 0)
+
static int nl80211_freq2channel(int freq)
{
static char * nl80211_ifname2phy(const char *ifname)
{
static char phy[32] = { 0 };
- struct nl80211_msg_conveyor *req;
memset(phy, 0, sizeof(phy));
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (req)
- {
- nl80211_send(req, nl80211_ifname2phy_cb, phy);
- nl80211_free(req);
- }
+ nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
+ nl80211_ifname2phy_cb, phy);
return phy[0] ? phy : NULL;
}
((ifidx < 0) || (cifidx < ifidx)))
{
ifidx = cifidx;
- strncpy(nif, e->d_name, sizeof(nif));
+ strncpy(nif, e->d_name, sizeof(nif) - 1);
}
}
}
static int nl80211_get_mode(const char *ifname, int *buf)
{
char *res;
- struct nl80211_msg_conveyor *req;
- res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
*buf = IWINFO_OPMODE_UNKNOWN;
- if (req)
- {
- nl80211_send(req, nl80211_get_mode_cb, buf);
- nl80211_free(req);
- }
+ res = nl80211_phy2ifname(ifname);
+
+ nl80211_request(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0,
+ nl80211_get_mode_cb, buf);
return (*buf == IWINFO_OPMODE_UNKNOWN) ? -1 : 0;
}
static char * nl80211_ifadd(const char *ifname)
{
- char *rv = NULL, path[PATH_MAX];
+ char path[PATH_MAX];
static char nif[IFNAMSIZ] = { 0 };
struct nl80211_msg_conveyor *req;
FILE *sysfs;
fclose(sysfs);
}
- rv = nif;
+ return nif;
nla_put_failure:
nl80211_free(req);
}
- return rv;
+ return NULL;
}
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)
NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname);
nl80211_send(req, NULL, NULL);
+ return;
nla_put_failure:
nl80211_free(req);
if (phy)
{
snprintf(buf, sizeof(buf), "/var/run/wifi-%s.pid", phy);
- if ((fd = open(buf, O_RDONLY)) > 0)
+ if ((fd = open(buf, O_RDONLY)) >= 0)
{
if (read(fd, buf, sizeof(buf)) > 0)
pid = atoi(buf);
static int nl80211_get_ssid(const char *ifname, char *buf)
{
char *res;
- struct nl80211_msg_conveyor *req;
- struct nl80211_ssid_bssid sb;
+ struct nl80211_ssid_bssid sb = { .ssid = (unsigned char *)buf };
/* try to find ssid from scan dump results */
res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
-
- sb.ssid = (unsigned char *)buf;
- *buf = 0;
+ sb.ssid[0] = 0;
- if (req)
- {
- nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
- nl80211_free(req);
- }
+ nl80211_request(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP,
+ nl80211_get_ssid_bssid_cb, &sb);
/* failed, try to find from hostapd info */
- if (*buf == 0)
- nl80211_hostapd_query(ifname, "ssid", buf, IWINFO_ESSID_MAX_SIZE + 1);
+ if (sb.ssid[0] == 0)
+ nl80211_hostapd_query(ifname, "ssid", sb.ssid,
+ IWINFO_ESSID_MAX_SIZE + 1);
- return (*buf == 0) ? -1 : 0;
+ return (sb.ssid[0] == 0) ? -1 : 0;
}
static int nl80211_get_bssid(const char *ifname, char *buf)
{
char *res, bssid[sizeof("FF:FF:FF:FF:FF:FF\0")];
- struct nl80211_msg_conveyor *req;
- struct nl80211_ssid_bssid sb;
+ struct nl80211_ssid_bssid sb = { };
/* try to find bssid from scan dump results */
res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
-
- sb.ssid = NULL;
- sb.bssid[0] = 0;
- if (req)
- {
- nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
- nl80211_free(req);
- }
+ nl80211_request(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP,
+ nl80211_get_ssid_bssid_cb, &sb);
/* failed, try to find mac from hostapd info */
if ((sb.bssid[0] == 0) &&
static int nl80211_get_frequency(const char *ifname, int *buf)
{
char *res, channel[4], hwmode[2];
- struct nl80211_msg_conveyor *req;
/* try to find frequency from interface info */
res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
*buf = 0;
- if (req)
- {
- nl80211_send(req, nl80211_get_frequency_info_cb, buf);
- nl80211_free(req);
- }
+ nl80211_request(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0,
+ nl80211_get_frequency_info_cb, buf);
/* failed, try to find frequency from hostapd info */
if ((*buf == 0) &&
if (*buf == 0)
{
res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
- if (req)
- {
- nl80211_send(req, nl80211_get_frequency_scan_cb, buf);
- nl80211_free(req);
- }
+ nl80211_request(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP,
+ nl80211_get_frequency_scan_cb, buf);
}
return (*buf == 0) ? -1 : 0;
static int nl80211_get_txpower(const char *ifname, int *buf)
{
char *res;
- struct nl80211_msg_conveyor *req;
res = nl80211_phy2ifname(ifname);
- req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
+ *buf = 0;
- if (req)
- {
- *buf = 0;
- nl80211_send(req, nl80211_get_txpower_cb, buf);
- nl80211_free(req);
- if (*buf)
- return 0;
- }
+ if (nl80211_request(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0,
+ nl80211_get_txpower_cb, buf))
+ return -1;
- return -1;
+ return 0;
}
if (sinfo[NL80211_STA_INFO_SIGNAL])
{
dbm = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
- rr->rssi = rr->rssi ? (int8_t)((rr->rssi + dbm) / 2) : dbm;
+ rr->rssi = (rr->rssi * rr->rssi_samples + dbm) / (rr->rssi_samples + 1);
+ rr->rssi_samples++;
}
if (sinfo[NL80211_STA_INFO_TX_BITRATE])
if (rinfo[NL80211_RATE_INFO_BITRATE])
{
mbit = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
- rr->rate = rr->rate
- ? (int16_t)((rr->rate + mbit) / 2) : mbit;
+ rr->rate = (rr->rate * rr->rate_samples + mbit) / (rr->rate_samples + 1);
+ rr->rate_samples++;
}
}
}
{
DIR *d;
struct dirent *de;
- struct nl80211_msg_conveyor *req;
- r->rssi = 0;
- r->rate = 0;
+ memset(r, 0, sizeof(*r));
if ((d = opendir("/sys/class/net")) != NULL)
{
(!de->d_name[strlen(ifname)] ||
!strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
{
- req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
- NLM_F_DUMP);
-
- if (req)
- {
- nl80211_send(req, nl80211_fill_signal_cb, r);
- nl80211_free(req);
- }
+ nl80211_request(de->d_name, NL80211_CMD_GET_STATION,
+ NLM_F_DUMP, nl80211_fill_signal_cb, r);
}
}
nl80211_fill_signal(ifname, &rr);
- if (rr.rate)
+ if (rr.rate_samples)
{
*buf = (rr.rate * 100);
return 0;
nl80211_fill_signal(ifname, &rr);
- if (rr.rssi)
+ if (rr.rssi_samples)
{
*buf = rr.rssi;
return 0;
static int nl80211_get_noise(const char *ifname, int *buf)
{
- int8_t noise;
- struct nl80211_msg_conveyor *req;
+ int8_t noise = 0;
- req = nl80211_msg(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP);
- if (req)
- {
- noise = 0;
+ if (nl80211_request(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP,
+ nl80211_get_noise_cb, &noise))
+ goto out;
- nl80211_send(req, nl80211_get_noise_cb, &noise);
- nl80211_free(req);
-
- if (noise)
- {
- *buf = noise;
- return 0;
- }
- }
+ *buf = noise;
+ return 0;
+out:
+ *buf = 0;
return -1;
}
}
+static void nl80211_parse_rateinfo(struct nlattr **ri,
+ struct iwinfo_rate_entry *re)
+{
+ if (ri[NL80211_RATE_INFO_BITRATE32])
+ re->rate = nla_get_u32(ri[NL80211_RATE_INFO_BITRATE32]) * 100;
+ 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])
+ {
+ re->is_vht = 1;
+ re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_VHT_MCS]);
+
+ if (ri[NL80211_RATE_INFO_VHT_NSS])
+ re->nss = nla_get_u8(ri[NL80211_RATE_INFO_VHT_NSS]);
+ }
+ else if (ri[NL80211_RATE_INFO_MCS])
+ {
+ re->is_ht = 1;
+ re->mcs = nla_get_u8(ri[NL80211_RATE_INFO_MCS]);
+ }
+
+ if (ri[NL80211_RATE_INFO_5_MHZ_WIDTH])
+ re->mhz = 5;
+ else if (ri[NL80211_RATE_INFO_10_MHZ_WIDTH])
+ re->mhz = 10;
+ else if (ri[NL80211_RATE_INFO_40_MHZ_WIDTH])
+ re->mhz = 40;
+ else if (ri[NL80211_RATE_INFO_80_MHZ_WIDTH])
+ re->mhz = 80;
+ else if (ri[NL80211_RATE_INFO_80P80_MHZ_WIDTH] ||
+ ri[NL80211_RATE_INFO_160_MHZ_WIDTH])
+ re->mhz = 160;
+ else
+ re->mhz = 20;
+
+ if (ri[NL80211_RATE_INFO_SHORT_GI])
+ re->is_short_gi = 1;
+
+ re->is_40mhz = (re->mhz == 40);
+}
+
static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg)
{
struct nl80211_array_buf *arr = arg;
[NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
[NL80211_STA_INFO_STA_FLAGS] =
{ .minlen = sizeof(struct nl80211_sta_flag_update) },
+ [NL80211_STA_INFO_EXPECTED_THROUGHPUT] = { .type = NLA_U32 },
};
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
if (sinfo[NL80211_STA_INFO_RX_BITRATE] &&
!nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy))
- {
- if (rinfo[NL80211_RATE_INFO_BITRATE])
- e->rx_rate.rate =
- nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
-
- if (rinfo[NL80211_RATE_INFO_MCS])
- e->rx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
-
- if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
- e->rx_rate.is_40mhz = 1;
-
- if (rinfo[NL80211_RATE_INFO_SHORT_GI])
- e->rx_rate.is_short_gi = 1;
- }
+ nl80211_parse_rateinfo(rinfo, &e->rx_rate);
if (sinfo[NL80211_STA_INFO_TX_BITRATE] &&
!nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
- {
- if (rinfo[NL80211_RATE_INFO_BITRATE])
- e->tx_rate.rate =
- nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
-
- if (rinfo[NL80211_RATE_INFO_MCS])
- e->tx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
-
- if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
- e->tx_rate.is_40mhz = 1;
-
- if (rinfo[NL80211_RATE_INFO_SHORT_GI])
- e->tx_rate.is_short_gi = 1;
- }
+ nl80211_parse_rateinfo(rinfo, &e->tx_rate);
if (sinfo[NL80211_STA_INFO_RX_BYTES])
e->rx_bytes = nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
if (sinfo[NL80211_STA_INFO_T_OFFSET])
e->t_offset = nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET]);
+ if (sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT])
+ e->thr = nla_get_u32(sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT]);
+
/* Station flags */
if (sinfo[NL80211_STA_INFO_STA_FLAGS])
{
DIR *d;
int i, noise = 0;
struct dirent *de;
- struct nl80211_msg_conveyor *req;
struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
struct iwinfo_assoclist_entry *e;
(!de->d_name[strlen(ifname)] ||
!strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
{
- req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
- NLM_F_DUMP);
-
- if (req)
- {
- nl80211_send(req, nl80211_get_assoclist_cb, &arr);
- nl80211_free(req);
- }
+ nl80211_request(de->d_name, NL80211_CMD_GET_STATION,
+ NLM_F_DUMP, nl80211_get_assoclist_cb, &arr);
}
}
static int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
{
- int ch_cur;
+ 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))
ch_cur = 0;
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (req)
- {
- /* initialize the value pointer with channel for callback */
- dbm_max = ch_cur;
+ /* initialize the value pointer with channel for callback */
+ dbm_max = ch_cur;
- nl80211_send(req, nl80211_get_txpwrlist_cb, &dbm_max);
- nl80211_free(req);
- }
+ err = nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
+ nl80211_get_txpwrlist_cb, &dbm_max);
- if (dbm_max > 0)
+ if (!err)
{
for (dbm_cur = 0, dbm_cnt = 0;
dbm_cur < dbm_max;
static int nl80211_get_scanlist_nl(const char *ifname, char *buf, int *len)
{
- struct nl80211_msg_conveyor *req;
struct nl80211_scanlist sl = { .e = (struct iwinfo_scanlist_entry *)buf };
- req = nl80211_msg(ifname, NL80211_CMD_TRIGGER_SCAN, 0);
- if (req)
- {
- nl80211_send(req, NULL, NULL);
- nl80211_free(req);
- }
+ if (nl80211_request(ifname, NL80211_CMD_TRIGGER_SCAN, 0, NULL, NULL))
+ goto out;
- nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS);
+ if (nl80211_wait("nl80211", "scan",
+ NL80211_CMD_NEW_SCAN_RESULTS, NL80211_CMD_SCAN_ABORTED))
+ goto out;
- req = nl80211_msg(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
- if (req)
- {
- nl80211_send(req, nl80211_get_scanlist_cb, &sl);
- nl80211_free(req);
- }
+ if (nl80211_request(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP,
+ nl80211_get_scanlist_cb, &sl))
+ goto out;
*len = sl.len * sizeof(struct iwinfo_scanlist_entry);
- return *len ? 0 : -1;
+ return 0;
+
+out:
+ *len = 0;
+ return -1;
}
static int wpasupp_ssid_decode(const char *in, char *out, int outlen)
/* is another unrelated event, retry */
tries--;
}
+
+ /* got a failure reply */
+ else if (!strcmp(reply, "FAIL-BUSY\n"))
+ {
+ break;
+ }
}
/* receive and parse scan results if the wait above didn't time out */
- if (ready && nl80211_wpactl_recv(sock, reply, sizeof(reply)) > 0)
+ while (ready && nl80211_wpactl_recv(sock, reply, sizeof(reply)) > 0)
{
+ /* received an event notification, receive again */
+ if (reply[0] == '<')
+ continue;
+
nl80211_get_quality_max(ifname, &qmax);
for (line = strtok_r(reply, "\n", &pos);
}
*len = count * sizeof(struct iwinfo_scanlist_entry);
+ break;
}
close(sock);
int bands_remain, freqs_remain;
struct nl80211_array_buf *arr = arg;
- struct iwinfo_freqlist_entry *e = arr->buf;
+ struct iwinfo_freqlist_entry *e;
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;
- nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
- {
- nla_parse(bands, NL80211_BAND_ATTR_MAX,
- nla_data(band), nla_len(band), NULL);
+ e = arr->buf;
+ e += arr->count;
- nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
+ if (attr[NL80211_ATTR_WIPHY_BANDS]) {
+ nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
{
- nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(freq), nla_len(freq), NULL);
-
- if (!freqs[NL80211_FREQUENCY_ATTR_FREQ] ||
- freqs[NL80211_FREQUENCY_ATTR_DISABLED])
- continue;
-
- 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;
+ nla_parse(bands, NL80211_BAND_ATTR_MAX,
+ nla_data(band), nla_len(band), NULL);
- e++;
- arr->count++;
+ 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] ||
+ freqs[NL80211_FREQUENCY_ATTR_DISABLED])
+ continue;
+
+ 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_HT40PLUS;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_80MHZ])
+ e->flags |= IWINFO_FREQ_NO_80MHZ;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_160MHZ])
+ e->flags |= IWINFO_FREQ_NO_160MHZ;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_20MHZ])
+ e->flags |= IWINFO_FREQ_NO_20MHZ;
+ if (freqs[NL80211_FREQUENCY_ATTR_NO_10MHZ])
+ e->flags |= IWINFO_FREQ_NO_10MHZ;
+
+ e++;
+ arr->count++;
+ }
+ }
}
}
static int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
{
- struct nl80211_msg_conveyor *req;
+ struct nl80211_msg_conveyor *cv;
struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
+ uint32_t features = nl80211_get_protocol_features(ifname);
+ int flags;
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (req)
- {
- nl80211_send(req, nl80211_get_freqlist_cb, &arr);
- nl80211_free(req);
- }
+ flags = features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP ? NLM_F_DUMP : 0;
+ cv = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, flags);
+ if (!cv)
+ goto out;
- if (arr.count > 0)
- {
- *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
- return 0;
- }
+ NLA_PUT_FLAG(cv->msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
+ if (nl80211_send(cv, nl80211_get_freqlist_cb, &arr))
+ goto out;
+ *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
+ return 0;
+
+nla_put_failure:
+ nl80211_free(cv);
+out:
+ *len = 0;
return -1;
}
static int nl80211_get_country(const char *ifname, char *buf)
{
- int rv = -1;
- struct nl80211_msg_conveyor *req;
-
- req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
- if (req)
- {
- nl80211_send(req, nl80211_get_country_cb, buf);
- nl80211_free(req);
-
- if (buf[0])
- rv = 0;
- }
+ if (nl80211_request(ifname, NL80211_CMD_GET_REG, 0,
+ nl80211_get_country_cb, buf))
+ return -1;
- return rv;
+ return 0;
}
static int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
static int nl80211_get_hwmodelist(const char *ifname, int *buf)
{
- struct nl80211_msg_conveyor *req;
struct nl80211_modes m = { 0 };
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (req)
- {
- nl80211_send(req, nl80211_get_modelist_cb, &m);
- nl80211_free(req);
- }
+ if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
+ nl80211_get_modelist_cb, &m))
+ goto out;
- if (m.ok)
- {
- *buf = m.hw;
- return 0;
- }
+ if (!m.ok)
+ goto out;
+ *buf = m.hw;
+ return 0;
+
+out:
+ *buf = 0;
return -1;
}
static int nl80211_get_htmodelist(const char *ifname, int *buf)
{
- struct nl80211_msg_conveyor *req;
struct nl80211_modes m = { 0 };
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (req)
- {
- nl80211_send(req, nl80211_get_modelist_cb, &m);
- nl80211_free(req);
- }
+ if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
+ nl80211_get_modelist_cb, &m))
+ goto out;
- if (m.ok)
- {
- *buf = m.ht;
- return 0;
- }
+ if (!m.ok)
+ goto out;
+ *buf = m.ht;
+ return 0;
+
+out:
+ *buf = 0;
return -1;
}
static int nl80211_get_mbssid_support(const char *ifname, int *buf)
{
- struct nl80211_msg_conveyor *req;
-
- req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
- if (!req)
+ if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
+ nl80211_get_ifcomb_cb, buf))
return -1;
- nl80211_send(req, nl80211_get_ifcomb_cb, buf);
- nl80211_free(req);
return 0;
}
static int nl80211_get_hardware_id(const char *ifname, char *buf)
{
- int rv;
+ int rv = -1;
char *res;
/* Got a radioX pseudo interface, find some interface on it or create one */