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_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;
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 );
+ 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);
return err;
}
+#define nl80211_wait(family, group, ...) \
+ __nl80211_wait(family, group, __VA_ARGS__, 0)
+
static int nl80211_freq2channel(int freq)
{
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;
- r->rssi = 0;
- r->rate = 0;
+ memset(r, 0, sizeof(*r));
if ((d = opendir("/sys/class/net")) != NULL)
{
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;
[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_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])
{
if (nl80211_request(ifname, NL80211_CMD_TRIGGER_SCAN, 0, NULL, NULL))
goto out;
- if (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;
if (nl80211_request(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP,
}
/* 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);
static int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
{
+ struct nl80211_msg_conveyor *cv;
struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
+ uint32_t features = nl80211_get_protocol_features(ifname);
+ int flags;
- if (nl80211_request(ifname, NL80211_CMD_GET_WIPHY, 0,
- nl80211_get_freqlist_cb, &arr))
+ 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;
+
+ 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;