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)
{
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 *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;