Skip to contentSkip to conversation

wiphy: Add wiphy_get_supported_rates

PATCH Applied Andrew Zaborowski 2 participants 13 messages Oct 24, 2019 – Oct 26, 2019

lore
Share & tools
lore
#0 lore raw

PATCH 1/8 wiphy: Add wiphy_get_supported_rates

Add code to parse the supported data rates info from the wiphy dumps and expose it for P2P's use with a getter function.

---
 src/wiphy.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/wiphy.h |  2 ++
 2 files changed, 76 insertions(+), 4 deletions(-)
src/wiphy.c +74 -4
index 9cb9ae66..12ec5d17 100644
@@ -76,6 +76,7 @@ struct wiphy {
 	struct watchlist state_watches;
 	uint8_t extended_capabilities[EXT_CAP_LEN + 2]; /* max bitmap size + IE header */
 	uint8_t *iftype_extended_capabilities[NUM_NL80211_IFTYPES];
+	uint8_t *supported_rates[NUM_NL80211_BANDS];
 	uint8_t rm_enabled_capabilities[7]; /* 5 size max + header */
 
 	bool support_scheduled_scan:1;
@@ -212,6 +213,9 @@ static void wiphy_free(void *data)
 	for (i = 0; i < NUM_NL80211_IFTYPES; i++)
 		l_free(wiphy->iftype_extended_capabilities[i]);
 
+	for (i = 0; i < NUM_NL80211_BANDS; i++)
+		l_free(wiphy->supported_rates[i]);
+
 	scan_freq_set_free(wiphy->supported_freqs);
 	watchlist_destroy(&wiphy->state_watches);
 	l_free(wiphy->model_str);
@@ -478,6 +482,14 @@ bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype)
 	return wiphy->supported_iftypes & (1 << (iftype - 1));
 }
 
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int band)
+{
+	if (band >= L_ARRAY_SIZE(wiphy->supported_rates))
+		return NULL;
+
+	return wiphy->supported_rates[band];
+}
+
 uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
 				wiphy_state_watch_func_t func,
 				void *user_data, wiphy_destroy_func_t destroy)
@@ -622,20 +634,70 @@ static void parse_supported_frequencies(struct wiphy *wiphy,
 	}
 }
 
+static uint8_t *parse_supported_rates(struct l_genl_attr *attr)
+{
+	uint16_t type;
+	uint16_t len;
+	const void *data;
+	struct l_genl_attr nested;
+	int count = 0;
+	uint8_t *ret;
+
+	if (!l_genl_attr_recurse(attr, &nested))
+		return NULL;
+
+	while (l_genl_attr_next(&nested, NULL, NULL, NULL))
+		count++;
+
+	if (!l_genl_attr_recurse(attr, &nested))
+		return NULL;
+
+	ret = l_malloc(count + 1);
+	ret[count] = 0;
+
+	count = 0;
+
+	while (l_genl_attr_next(&nested, NULL, NULL, NULL)) {
+		struct l_genl_attr nested2;
+
+		if (!l_genl_attr_recurse(&nested, &nested2)) {
+			l_free(ret);
+			return NULL;
+		}
+
+		while (l_genl_attr_next(&nested2, &type, &len, &data)) {
+			if (type != NL80211_BITRATE_ATTR_RATE || len != 4)
+				continue;
+
+			/*
+			 * Convert from the 100kb/s units reported by the
+			 * kernel to the 500kb/s used in 802.11 IEs.
+			 */
+			ret[count++] = *(const uint32_t *) data / 5;
+		}
+	}
+
+	return ret;
+}
+
 static void parse_supported_bands(struct wiphy *wiphy,
 						struct l_genl_attr *bands)
 {
-	uint16_t type, len;
-	const void *data;
+	uint16_t type;
 	struct l_genl_attr attr;
 
 	l_debug("");
 
-	while (l_genl_attr_next(bands, NULL, NULL, NULL)) {
+	while (l_genl_attr_next(bands, &type, NULL, NULL)) {
+		enum nl80211_band band = type;
+
+		if (band != NL80211_BAND_2GHZ && band != NL80211_BAND_5GHZ)
+			continue;
+
 		if (!l_genl_attr_recurse(bands, &attr))
 			continue;
 
-		while (l_genl_attr_next(&attr, &type, &len, &data)) {
+		while (l_genl_attr_next(&attr, &type, NULL, NULL)) {
 			struct l_genl_attr freqs;
 
 			switch (type) {
@@ -645,6 +707,14 @@ static void parse_supported_bands(struct wiphy *wiphy,
 
 				parse_supported_frequencies(wiphy, &freqs);
 				break;
+
+			case NL80211_BAND_ATTR_RATES:
+				if (wiphy->supported_rates[band])
+					continue;
+
+				wiphy->supported_rates[band] =
+					parse_supported_rates(&attr);
+				break;
 			}
 		}
 	}
src/wiphy.h +2 -0
index c109f0a8..a5133972 100644
@@ -66,6 +66,8 @@ bool wiphy_has_ext_feature(struct wiphy *wiphy, uint32_t feature);
 uint8_t wiphy_get_max_num_ssids_per_scan(struct wiphy *wiphy);
 uint32_t wiphy_get_max_roc_duration(struct wiphy *wiphy);
 bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype);
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy,
+						unsigned int band);
 bool wiphy_supports_adhoc_rsn(struct wiphy *wiphy);
 bool wiphy_can_offchannel_tx(struct wiphy *wiphy);
 bool wiphy_supports_qos_set_map(struct wiphy *wiphy);
Signature · 1 line
2.20.1
#1 lore raw

PATCH 2/8 scan: Hide CCK rates if no_cck_rates set

no_cck_rates is set in the scan parameters generally to make sure that the Probe Request frames are not sent at any of the 802.11b rates during active scans. With this patch we also omit those rates from the Supported Rates IEs, which is required by the p2p spec and also matches our flag's name.

---
 src/scan.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)
src/scan.c +34 -1
index a63c462a..2d54af12 100644
@@ -347,10 +347,43 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
 	if (flags)
 		l_genl_msg_append_attr(msg, NL80211_ATTR_SCAN_FLAGS, 4, &flags);
 
-	if (params->no_cck_rates)
+	if (params->no_cck_rates) {
+		static const uint8_t b_rates[] = { 2, 4, 11, 22 };
+		uint8_t *scan_rates;
+		const uint8_t *supported;
+		int i;
+		int count;
+
 		l_genl_msg_append_attr(msg, NL80211_ATTR_TX_NO_CCK_RATE, 0,
 					NULL);
 
+		/*
+		 * Assume if we're sending the probe requests at OFDM bit
+		 * rates we don't want to advertise support for 802.11b rates.
+		 */
+		supported = wiphy_get_supported_rates(sc->wiphy,
+							NL80211_BAND_2GHZ);
+		if (!supported) {
+			L_WARN_ON(true);
+			return msg;
+		}
+
+		scan_rates = l_malloc(strlen((const char *) supported));
+
+		for (i = 0, count = 0; supported[i]; i++)
+			if (!memchr(b_rates, supported[i],
+					L_ARRAY_SIZE(b_rates)))
+				scan_rates[count++] = supported[i];
+
+		L_WARN_ON(!count);
+
+		l_genl_msg_enter_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+		l_genl_msg_append_attr(msg, NL80211_BAND_2GHZ, count,
+					scan_rates);
+		l_genl_msg_leave_nested(msg);
+		l_free(scan_rates);
+	}
+
 	return msg;
 }
 
Signature · 1 line
2.20.1
#2 lore raw

PATCH 3/8 scan: Parse P2P IEs according to frame type

In reply to Andrew Zaborowski

Save the source frame type in struct scan_bss as it may affect how some of the data in the struct should be parsed. Also replace the P2P IE payload data in that struct with a union containing pre-parsed p2p attributes corresponding to the frame type.

This means users don't have to call the parsers in p2putil.c on that data, which wouldn't have worked anyway because we those parsers were assuming the raw concatenated P2P IEs as a parameter instead of the payload extracted with ie_tlv_extract_p2p_payload.

---
 src/scan.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-------
 src/scan.h | 17 ++++++++++--
 2 files changed, 84 insertions(+), 12 deletions(-)
src/scan.c +69 -10
index 2d54af12..2c676890 100644
@@ -45,6 +45,7 @@
 #include "src/nl80211cmd.h"
 #include "src/nl80211util.h"
 #include "src/util.h"
+#include "src/p2putil.h"
 #include "src/scan.h"
 
 #define SCAN_MAX_INTERVAL 320
@@ -987,6 +988,38 @@ static bool scan_parse_bss_information_elements(struct scan_bss *bss,
 		}
 	}
 
+	bss->wsc = ie_tlv_extract_wsc_payload(data, len, &bss->wsc_size);
+
+	switch (bss->source_frame) {
+	case SCAN_BSS_PROBE_RESP:
+	{
+		struct p2p_probe_resp info;
+
+		if (p2p_parse_probe_resp(data, len, &info) == 0)
+			bss->p2p_probe_resp_info = l_memdup(&info, sizeof(info));
+
+		break;
+	}
+	case SCAN_BSS_PROBE_REQ:
+	{
+		struct p2p_probe_req info;
+
+		if (p2p_parse_probe_req(data, len, &info) == 0)
+			bss->p2p_probe_req_info = l_memdup(&info, sizeof(info));
+
+		break;
+	}
+	case SCAN_BSS_BEACON:
+	{
+		struct p2p_beacon info;
+
+		if (p2p_parse_beacon(data, len, &info) == 0)
+			bss->p2p_beacon_info = l_memdup(&info, sizeof(info));
+
+		break;
+	}
+	}
+
 	return have_ssid;
 }
 
@@ -995,9 +1028,12 @@ static struct scan_bss *scan_parse_attr_bss(struct l_genl_attr *attr)
 	uint16_t type, len;
 	const void *data;
 	struct scan_bss *bss;
+	const uint8_t *ies = NULL;
+	size_t ies_len;
 
 	bss = l_new(struct scan_bss, 1);
 	bss->utilization = 127;
+	bss->source_frame = SCAN_BSS_BEACON;
 
 	while (l_genl_attr_next(attr, &type, &len, &data)) {
 		switch (type) {
@@ -1025,20 +1061,19 @@ static struct scan_bss *scan_parse_attr_bss(struct l_genl_attr *attr)
 
 			bss->signal_strength = *((int32_t *) data);
 			break;
+		case NL80211_BSS_PRESP_DATA:
+			bss->source_frame = SCAN_BSS_PROBE_RESP;
+			break;
 		case NL80211_BSS_INFORMATION_ELEMENTS:
-			if (!scan_parse_bss_information_elements(bss,
-								data, len))
-				goto fail;
-
-			bss->wsc = ie_tlv_extract_wsc_payload(data, len,
-								&bss->wsc_size);
-			bss->p2p = ie_tlv_extract_p2p_payload(data, len,
-								&bss->p2p_size);
-
+			ies = data;
+			ies_len = len;
 			break;
 		}
 	}
 
+	if (ies && !scan_parse_bss_information_elements(bss, ies, ies_len))
+		goto fail;
+
 	return bss;
 
 fail:
@@ -1198,9 +1233,33 @@ void scan_bss_free(struct scan_bss *bss)
 	l_free(bss->rsne);
 	l_free(bss->wpa);
 	l_free(bss->wsc);
-	l_free(bss->p2p);
 	l_free(bss->osen);
 	l_free(bss->rc_ie);
+
+	switch (bss->source_frame) {
+	case SCAN_BSS_PROBE_RESP:
+		if (!bss->p2p_probe_resp_info)
+			break;
+
+		p2p_free_probe_resp(bss->p2p_probe_resp_info);
+		l_free(bss->p2p_probe_resp_info);
+		break;
+	case SCAN_BSS_PROBE_REQ:
+		if (!bss->p2p_probe_req_info)
+			break;
+
+		p2p_free_probe_req(bss->p2p_probe_req_info);
+		l_free(bss->p2p_probe_req_info);
+		break;
+	case SCAN_BSS_BEACON:
+		if (!bss->p2p_beacon_info)
+			break;
+
+		p2p_free_beacon(bss->p2p_beacon_info);
+		l_free(bss->p2p_beacon_info);
+		break;
+	}
+
 	l_free(bss);
 }
 
src/scan.h +15 -2
index dabce95f..a3129dea 100644
@@ -40,6 +40,15 @@ typedef void (*scan_freq_set_func_t)(uint32_t freq, void *userdata);
 
 struct scan_freq_set;
 struct ie_rsn_info;
+struct p2p_probe_resp;
+struct p2p_probe_req;
+struct p2p_beacon;
+
+enum scan_bss_frame_type {
+	SCAN_BSS_PROBE_RESP,
+	SCAN_BSS_PROBE_REQ,
+	SCAN_BSS_BEACON,
+};
 
 struct scan_bss {
 	uint8_t addr[6];
@@ -51,8 +60,12 @@ struct scan_bss {
 	uint8_t *osen;
 	uint8_t *wsc;		/* Concatenated WSC IEs */
 	ssize_t wsc_size;	/* Size of Concatenated WSC IEs */
-	uint8_t *p2p;		/* Concatenated P2P IEs */
-	ssize_t p2p_size;	/* Size of Concatenated P2P IEs */
+	enum scan_bss_frame_type source_frame;
+	union {
+		struct p2p_probe_resp *p2p_probe_resp_info;
+		struct p2p_probe_req *p2p_probe_req_info;
+		struct p2p_beacon *p2p_beacon_info;
+	};
 	uint8_t mde[3];
 	uint8_t ssid[32];
 	uint8_t ssid_len;
Signature · 1 line
2.20.1
#3 lore raw

PATCH 4/8 scan: Add scan_bss_new_from_probe_req

In reply to Andrew Zaborowski
---
 src/scan.c | 27 +++++++++++++++++++++++++++
 src/scan.h |  6 ++++++
 2 files changed, 33 insertions(+)
src/scan.c +27 -0
index 2c676890..62f78130 100644
@@ -46,6 +46,7 @@
 #include "src/nl80211util.h"
 #include "src/util.h"
 #include "src/p2putil.h"
+#include "src/mpdu.h"
 #include "src/scan.h"
 
 #define SCAN_MAX_INTERVAL 320
@@ -1227,6 +1228,32 @@ static void scan_bss_compute_rank(struct scan_bss *bss)
 		bss->rank = irank;
 }
 
+struct scan_bss *scan_bss_new_from_probe_req(const struct mmpdu_header *mpdu,
+						const uint8_t *body,
+						size_t body_len,
+						uint32_t frequency, int rssi)
+
+{
+	struct scan_bss *bss;
+
+	bss = l_new(struct scan_bss, 1);
+	memcpy(bss->addr, mpdu->address_2, 6);
+	bss->utilization = 127;
+	bss->source_frame = SCAN_BSS_PROBE_REQ;
+	bss->frequency = frequency;
+	bss->signal_strength = rssi;
+
+	if (!scan_parse_bss_information_elements(bss, body, body_len))
+		goto fail;
+
+	scan_bss_compute_rank(bss);
+	return bss;
+
+fail:
+	scan_bss_free(bss);
+	return NULL;
+}
+
 void scan_bss_free(struct scan_bss *bss)
 {
 	l_free(bss->ext_supp_rates_ie);
src/scan.h +6 -0
index a3129dea..b602f731 100644
@@ -43,6 +43,7 @@ struct ie_rsn_info;
 struct p2p_probe_resp;
 struct p2p_probe_req;
 struct p2p_beacon;
+struct mmpdu_header;
 
 enum scan_bss_frame_type {
 	SCAN_BSS_PROBE_RESP,
@@ -134,6 +135,11 @@ int scan_bss_rank_compare(const void *a, const void *b, void *user);
 
 int scan_bss_get_rsn_info(const struct scan_bss *bss, struct ie_rsn_info *info);
 
+struct scan_bss *scan_bss_new_from_probe_req(const struct mmpdu_header *mpdu,
+						const uint8_t *body,
+						size_t body_len,
+						uint32_t frequency, int rssi);
+
 uint8_t scan_freq_to_channel(uint32_t freq, enum scan_band *out_band);
 uint32_t scan_channel_to_freq(uint8_t channel, enum scan_band band);
 enum scan_band scan_oper_class_to_band(const uint8_t *country,
Signature · 1 line
2.20.1
#4 lore raw

PATCH 5/8 nl80211util: Fail in nl80211_parse_attrs if attribute missing

In reply to Andrew Zaborowski

The users of this function expect an error return value if any of the attributes wanted was not present in the message.

---
 src/nl80211util.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
src/nl80211util.c +4 -1
index cac4de09..df895a77 100644
@@ -162,9 +162,12 @@ int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...)
 			ret = -EINVAL;
 			goto done;
 		}
+
+		l_queue_remove(entries, entry);
+		l_free(entry);
 	}
 
-	ret = 0;
+	ret = l_queue_isempty(entries) ? 0 : -ENOENT;
 
 done:
 	l_queue_destroy(entries, l_free);
Signature · 1 line
2.20.1
#5 lore raw

Re: [PATCH 5/8] nl80211util: Fail in nl80211_parse_attrs if attribute missing

Hi Andrew,

Quoted 5 lines · Andrew Zaborowski

The users of this function expect an error return value if any of the attributes wanted was not present in the message.

---
  src/nl80211util.c | 5 ++++-
  1 file changed, 4 insertions(+), 1 deletion(-)

Nice catch. Completely forgot about that check. I fixed this slightly differently in commit 3b937424db9009e3978fdcb1295f25088ffc48b6

Regards,
-Denis

#6 lore raw

PATCH 6/8 monitor: Fix the OUI check for P2P action frames

In reply to Andrew Zaborowski

wsc_wfa_oui is different from wifi_alliance_oui. Also use wsc_wfa_oui instead of a local copy in print_wsc_vendor_extension.

---
 monitor/nlmon.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
monitor/nlmon.c +3 -4
index 53e24d10..7ad1f5d6 100644
@@ -2633,7 +2633,6 @@ static void print_wsc_wfa_ext_attributes(unsigned int level, const char *label,
 
 static void print_wsc_vendor_extension(unsigned int level, const char *label,
 						const void *data, uint16_t size){
-	static const unsigned char wfa_ext[3] = { 0x00, 0x37, 0x2a };
 	const uint8_t *bytes = data;
 
 	if (size < 3) {
@@ -2641,7 +2640,7 @@ static void print_wsc_vendor_extension(unsigned int level, const char *label,
 		return;
 	}
 
-	if (memcmp(data, wfa_ext, sizeof(wfa_ext))) {
+	if (memcmp(data, wsc_wfa_oui, sizeof(wsc_wfa_oui))) {
 		print_attr(level, "%s: OUI: 0x%02x 0x%02x 0x%02x: len %u",
 				label, bytes[0], bytes[1], bytes[2], size);
 		print_hexdump(level + 1, data + 3, size - 3);
@@ -3930,7 +3929,7 @@ static void print_public_action_frame(unsigned int level, const uint8_t *body,
 	if (body_len < 5)
 		return;
 
-	if (!memcmp(oui, wsc_wfa_oui, 3) && oui[3] == 0x09) {
+	if (!memcmp(oui, wifi_alliance_oui, 3) && oui[3] == 0x09) {
 		if (body[0] != 9)
 			return;
 
@@ -4060,7 +4059,7 @@ static void print_action_mgmt_frame(unsigned int level,
 		if (!print_oui(level, oui))
 			return;
 
-		if (!memcmp(oui, wsc_wfa_oui, 3) && oui[3] == 0x09)
+		if (!memcmp(oui, wifi_alliance_oui, 3) && oui[3] == 0x09)
 			print_p2p_action_frame(level + 1, body + 5,
 						body_len - 5);
 	}
Signature · 1 line
2.20.1
#7 lore raw

PATCH 7/8 p2putil: Replace constants with wifi_alliance_oui

In reply to Andrew Zaborowski
---
 src/p2putil.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
src/p2putil.c +3 -3
index 79371168..7d1a7ad2 100644
@@ -2216,9 +2216,9 @@ static uint8_t *p2p_build_action_frame(bool public, uint8_t frame_subtype,
 	} else
 		ret[pos++] = 0x7f; /* Category: Vendor Specific */
 
-	ret[pos++] = 0x50;	/* OUI: Wi-Fi Alliance */
-	ret[pos++] = 0x6f;
-	ret[pos++] = 0x9a;
+	ret[pos++] = wifi_alliance_oui[0];
+	ret[pos++] = wifi_alliance_oui[1];
+	ret[pos++] = wifi_alliance_oui[2];
 	ret[pos++] = 0x09;	/* OUI type: Wi-Fi Alliance P2P v1.0 */
 	ret[pos++] = frame_subtype;
 	ret[pos++] = dialog_token;
Signature · 1 line
2.20.1
#8 lore raw

Re: [PATCH 7/8] p2putil: Replace constants with wifi_alliance_oui

Hi Andrew,

Quoted 4 lines · Andrew Zaborowski
---
  src/p2putil.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

Applied, thanks.

Regards,
-Denis

#9 lore raw

PATCH 8/8 p2putils: Fix length in Channel List parsing

In reply to Andrew Zaborowski
---
 src/p2putil.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
src/p2putil.c +1 -1
index 7d1a7ad2..ce53b2a2 100644
@@ -219,7 +219,7 @@ static bool extract_p2p_channel_list(const uint8_t *attr, size_t len,
 		l_queue_push_tail(out->channel_entries, entries);
 
 		attr += entries->n_channels;
-		len -= entries->n_channels;
+		len -= 2 + entries->n_channels;
 	}
 
 	return true;
Signature · 1 line
2.20.1
#10 lore raw

Re: [PATCH 8/8] p2putils: Fix length in Channel List parsing

Hi Andrew,

Quoted 4 lines · Andrew Zaborowski
---
  src/p2putil.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

Applied, thanks.

Regards,
-Denis

#11 lore raw
In reply to Andrew Zaborowski

Hi Andrew,

Quoted 12 lines · Andrew Zaborowski

Add code to parse the supported data rates info from the wiphy dumps and expose it for P2P's use with a getter function.

---
  src/wiphy.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++---
  src/wiphy.h |  2 ++
  2 files changed, 76 insertions(+), 4 deletions(-)
src/wiphy.c +0 -0
index 9cb9ae66..12ec5d17 100644

src/wiphy.c struct wiphy { · line 79

Quoted 4 lines
src/wiphy.c +1 -0
@@ -76,6 +76,7 @@ struct wiphy {
  	struct watchlist state_watches;
  	uint8_t extended_capabilities[EXT_CAP_LEN + 2]; /* max bitmap size + IE header */
  	uint8_t *iftype_extended_capabilities[NUM_NL80211_IFTYPES];
+	uint8_t *supported_rates[NUM_NL80211_BANDS];

So bit rates are uint32 in nl80211 and a uint16 in the kernel. How will this work to compress a 16 bit value in 8 bits, even if we divide by 5?

Quoted 42 lines
src/wiphy.c +21 -0
  	uint8_t rm_enabled_capabilities[7]; /* 5 size max + header */
 
  	bool support_scheduled_scan:1;
@@ -212,6 +213,9 @@ static void wiphy_free(void *data)
  	for (i = 0; i < NUM_NL80211_IFTYPES; i++)
  		l_free(wiphy->iftype_extended_capabilities[i]);
 
+	for (i = 0; i < NUM_NL80211_BANDS; i++)
+		l_free(wiphy->supported_rates[i]);
+
  	scan_freq_set_free(wiphy->supported_freqs);
  	watchlist_destroy(&wiphy->state_watches);
  	l_free(wiphy->model_str);
@@ -478,6 +482,14 @@ bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype)
  	return wiphy->supported_iftypes & (1 << (iftype - 1));
  }
 
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int band)
+{
+	if (band >= L_ARRAY_SIZE(wiphy->supported_rates))
+		return NULL;
+
+	return wiphy->supported_rates[band];
+}
+
  uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
  				wiphy_state_watch_func_t func,
  				void *user_data, wiphy_destroy_func_t destroy)
@@ -622,20 +634,70 @@ static void parse_supported_frequencies(struct wiphy *wiphy,
  	}
  }
 
+static uint8_t *parse_supported_rates(struct l_genl_attr *attr)
+{
+	uint16_t type;
+	uint16_t len;
+	const void *data;
+	struct l_genl_attr nested;
+	int count = 0;
+	uint8_t *ret;
+
+	if (!l_genl_attr_recurse(attr, &nested))

src/wiphy.c static void parse_supported_frequencies(struct wiphy *wiphy, · line 656

Quoted 10 lines
src/wiphy.c +10 -0
+		return NULL;
+
+	while (l_genl_attr_next(&nested, NULL, NULL, NULL))
+		count++;
+
+	if (!l_genl_attr_recurse(attr, &nested))
+		return NULL;
+
+	ret = l_malloc(count + 1);
+	ret[count] = 0;

So I know you use this to obtain the array size using strlen later. But man that is completely non-obvious. Maybe you should just make the supported rates length an out parameter in wiphy_get_supported_rates.

Regards,
-Denis

#12 lore raw

Hi Denis,

Quoted 5 lines · Denis Kenzior
Quoted 1 line · Andrew Zaborowski

+ uint8_t *supported_rates[NUM_NL80211_BANDS];

So bit rates are uint32 in nl80211 and a uint16 in the kernel. How will this work to compress a 16 bit value in 8 bits, even if we divide by 5?

802.11 uses 8 bits per bit rate in the Supported Rates and Extended Supported Rates IEs with 500kb/s steps. The same format is used in NL80211_ATTR_SCAN_SUPP_RATES, NL80211_TXRATE_LEGACY, NL80211_ATTR_STA_SUPPORTED_RATES and NL80211_ATTR_BSS_BASIC_RATES. I can change to 16 bits and 100kb/s steps if you prefer.

Quoted 49 lines
Quoted 49 lines

uint8_t rm_enabled_capabilities[7]; /* 5 size max + header */

bool support_scheduled_scan:1;

src/wiphy.c +27 -0
@@ -212,6 +213,9 @@ static void wiphy_free(void *data)
      for (i = 0; i < NUM_NL80211_IFTYPES; i++)
              l_free(wiphy->iftype_extended_capabilities[i]);
 
+     for (i = 0; i < NUM_NL80211_BANDS; i++)
+             l_free(wiphy->supported_rates[i]);
+
      scan_freq_set_free(wiphy->supported_freqs);
      watchlist_destroy(&wiphy->state_watches);
      l_free(wiphy->model_str);
@@ -478,6 +482,14 @@ bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype)
      return wiphy->supported_iftypes & (1 << (iftype - 1));
  }
 
+const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int band)
+{
+     if (band >= L_ARRAY_SIZE(wiphy->supported_rates))
+             return NULL;
+
+     return wiphy->supported_rates[band];
+}
+
  uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
                              wiphy_state_watch_func_t func,
                              void *user_data, wiphy_destroy_func_t destroy)
@@ -622,20 +634,70 @@ static void parse_supported_frequencies(struct wiphy *wiphy,
      }
  }
 
+static uint8_t *parse_supported_rates(struct l_genl_attr *attr)
+{
+     uint16_t type;
+     uint16_t len;
+     const void *data;
+     struct l_genl_attr nested;
+     int count = 0;
+     uint8_t *ret;
+
+     if (!l_genl_attr_recurse(attr, &nested))
+             return NULL;
+
+     while (l_genl_attr_next(&nested, NULL, NULL, NULL))
+             count++;
+
+     if (!l_genl_attr_recurse(attr, &nested))
Quoted 8 lines

src/wiphy.c static void parse_supported_frequencies(struct wiphy *wiphy, · line 656

Quoted 4 lines
src/wiphy.c +4 -0
+             return NULL;
+
+     ret = l_malloc(count + 1);
+     ret[count] = 0;

So I know you use this to obtain the array size using strlen later. But man that is completely non-obvious. Maybe you should just make the supported rates length an out parameter in wiphy_get_supported_rates.

Ok. Or we can do both things.

Best regards