ie: Remove old data rate estimation utilities

This commit is contained in:
Denis Kenzior 2021-06-03 22:15:45 -05:00
parent 297cde85bc
commit 647f1e9b91
2 changed files with 0 additions and 456 deletions

449
src/ie.c
View File

@ -31,7 +31,6 @@
#include "ell/useful.h"
#include "src/util.h"
#include "src/crypto.h"
#include "src/band.h"
#include "src/ie.h"
const unsigned char ieee_oui[3] = { 0x00, 0x0f, 0xac };
@ -1632,454 +1631,6 @@ int ie_parse_bss_load_from_data(const uint8_t *data, uint8_t len,
out_channel_utilization, out_admission_capacity);
}
/*
* We have to store this mapping since basic rates don't come with a convenient
* MCS index. Rates are stored as they are encoded in the Supported Rates IE.
* This does not include non 802.11g data rates, e.g. 1/2/4Mbps. This data was
* taken from 802.11 Section 17.3.10.2 and Table 10-7.
*
* Section 17.3.10.2 defines minimum RSSI for modulations, and Table
* 10-7 defines reference rates for the different modulations. Together we
* have minimum RSSI required for a given data rate.
*/
struct basic_rate_map {
int32_t rssi;
uint8_t rate;
};
/*
* Rates are stored in 500Kbps increments. This is how the IE encodes the data
* so its more convenient to match by this encoding. The actual data rate is
* converted to Mbps after we find a match
*/
static const struct basic_rate_map rate_rssi_map[] = {
{ -82, 12 },
{ -81, 18 },
{ -79, 24 },
{ -77, 36 },
{ -74, 48 },
{ -70, 72 },
{ -66, 96 },
{ -65, 108 },
};
static int ie_parse_supported_rates_from_data(const uint8_t *supp_rates_ie,
const uint8_t *ext_supp_rates_ie,
int32_t rssi, uint64_t *data_rate)
{
uint8_t max_rate = 0;
uint8_t highest = 0;
const uint8_t *rates;
unsigned int len;
unsigned int i;
/* Find highest rates possible with our RSSI */
for (i = 0; i < L_ARRAY_SIZE(rate_rssi_map); i++) {
const struct basic_rate_map *map = &rate_rssi_map[i];
if (rssi < map->rssi)
break;
max_rate = map->rate;
}
/*
* Find highest rate in Supported Rates IE. These IEs have at least
* been verfied that the length is within the buffer bounds (as has
* ext_supp_rates_ie).
*/
if (supp_rates_ie) {
len = supp_rates_ie[1];
if (len == 0)
return -EINVAL;
rates = supp_rates_ie + 2;
for (i = 0; i < len; i++) {
uint8_t r = rates[i] & 0x7f;
if (r <= max_rate && r > highest)
highest = r;
}
}
/* Find highest rate in Extended Supported Rates IE */
if (ext_supp_rates_ie) {
len = ext_supp_rates_ie[1];
if (len == 0)
return -EINVAL;
rates = ext_supp_rates_ie + 2;
for (i = 0; i < len; i++) {
uint8_t r = rates[i] & 0x7f;
if (r <= max_rate && r > highest)
highest = r;
}
}
if (highest)
*data_rate = (highest / 2) * 1000000;
else
*data_rate = (max_rate / 2) * 1000000;
return 0;
}
static int ie_parse_ht_capability(struct ie_tlv_iter *iter, int32_t rssi,
uint64_t *data_rate)
{
unsigned int len;
const uint8_t *data;
uint8_t ht_cap;
int i;
uint64_t highest_rate = 0;
bool support_40mhz;
bool short_gi_20mhz;
bool short_gi_40mhz;
len = ie_tlv_iter_get_length(iter);
if (len < 26)
return -EINVAL;
if (ie_tlv_iter_get_tag(iter) != IE_TYPE_HT_CAPABILITIES)
return -EINVAL;
data = ie_tlv_iter_get_data(iter);
/* Parse out channel width set and short GI */
ht_cap = l_get_u8(data++);
support_40mhz = test_bit(&ht_cap, 1);
short_gi_20mhz = test_bit(&ht_cap, 5);
short_gi_40mhz = test_bit(&ht_cap, 6);
data += 2;
/*
* TODO: Support MCS values 32 - 76
*
* The MCS values > 31 do not follow the same pattern since they use
* unequal modulation per spatial stream. These higher MCS values
* actually don't follow a pattern at all, since each stream can have a
* different modulation a higher MCS value does not mean higher
* throughput. For this reason these MCS indexes are left out.
*/
for (i = 31; i >= 0; i--) {
uint64_t drate;
if (!test_bit(data, i))
continue;
if (!support_40mhz)
goto check_20;
if (band_ofdm_rate(i % 8, OFDM_CHANNEL_WIDTH_40MHZ,
rssi, (i / 8) + 1, short_gi_40mhz, &drate)) {
*data_rate = drate;
return 0;
}
check_20:
if (!band_ofdm_rate(i % 8, OFDM_CHANNEL_WIDTH_20MHZ,
rssi, (i / 8) + 1, short_gi_20mhz, &drate))
continue;
if (!support_40mhz) {
*data_rate = drate;
return 0;
}
if (drate > highest_rate)
highest_rate = drate;
}
if (!highest_rate)
return -ENOTSUP;
*data_rate = highest_rate;
return 0;
}
static int ie_parse_ht_capability_from_data(const uint8_t *data, uint8_t len,
int32_t rssi, uint64_t *data_rate)
{
struct ie_tlv_iter iter;
uint8_t tag;
ie_tlv_iter_init(&iter, data, len);
if (!ie_tlv_iter_next(&iter))
return -EMSGSIZE;
tag = ie_tlv_iter_get_tag(&iter);
if (tag != IE_TYPE_HT_CAPABILITIES)
return -EPROTOTYPE;
return ie_parse_ht_capability(&iter, rssi, data_rate);
}
/*
* IEEE 802.11 - Table 9-250
*
* For simplicity, we are ignoring the Extended BSS BW support, per NOTE 11:
*
* NOTE 11-A receiving STA in which dot11VHTExtendedNSSCapable is false will
* ignore the Extended NSS BW Support subfield and effectively evaluate this
* table only at the entries where Extended NSS BW Support is 0.
*
* This also allows us to group the 160/80+80 widths together, since they are
* the same when Extended NSS BW is zero.
*/
static const uint8_t vht_width_map[3][4] = {
[0] = { 1, 1, 1, 0 },
[1] = { 1, 1, 1, 1 },
[2] = { 1, 1, 1, 1 },
};
static int ie_parse_vht_capability(struct ie_tlv_iter *vht_iter,
struct ie_tlv_iter *ht_iter, int32_t rssi,
uint64_t *data_rate)
{
int width;
int bitoffset;
int mcs;
unsigned int nss;
unsigned int len;
const uint8_t *data;
uint8_t channel_width_set;
uint8_t rx_mcs_map[2];
uint8_t tx_mcs_map[2];
unsigned int max_rx_mcs = 0;
unsigned int rx_nss = 1;
unsigned int max_tx_mcs = 0;
unsigned int tx_nss = 1;
uint8_t ht_cap;
bool short_gi_20mhz;
bool short_gi_40mhz;
bool short_gi_80mhz;
bool short_gi_160mhz;
uint64_t highest_rate = 0;
/* grab the short GI bits from the HT IE */
len = ie_tlv_iter_get_length(ht_iter);
if (len != 26)
return -EINVAL;
data = ie_tlv_iter_get_data(ht_iter);
ht_cap = l_get_u8(data);
short_gi_20mhz = test_bit(&ht_cap, 5);
short_gi_40mhz = test_bit(&ht_cap, 6);
/* now move onto VHT */
len = ie_tlv_iter_get_length(vht_iter);
if (len != 12)
return -EINVAL;
data = ie_tlv_iter_get_data(vht_iter);
channel_width_set = bit_field(*data, 2, 2);
short_gi_80mhz = bit_field(*data, 5, 1);
short_gi_160mhz = bit_field(*data, 6, 1);
data += 4;
rx_mcs_map[0] = *data++;
rx_mcs_map[1] = *data++;
data += 2;
tx_mcs_map[0] = *data++;
tx_mcs_map[1] = *data++;
/* NSS->MCS map values are grouped in 2-bit values */
for (bitoffset = 14; bitoffset >= 0; bitoffset -= 2) {
uint8_t rx_val = bit_field(rx_mcs_map[bitoffset / 8],
bitoffset % 8, 2);
uint8_t tx_val = bit_field(tx_mcs_map[bitoffset / 8],
bitoffset % 8, 2);
/*
* 0 indicates support for MCS 0-7
* 1 indicates support for MCS 0-8
* 2 indicates support for MCS 0-9
*
* Therefore 7 + rx/tx_val gives us our max MCS index.
*/
if (!max_rx_mcs && rx_val < 3) {
max_rx_mcs = 7 + rx_val;
rx_nss = (bitoffset / 2) + 1;
}
if (!max_tx_mcs && tx_val < 3) {
max_tx_mcs = 7 + tx_val;
tx_nss = (bitoffset / 2) + 1;
}
if (max_rx_mcs && max_tx_mcs)
break;
}
if (!max_rx_mcs && !max_tx_mcs)
return -EINVAL;
/*
* Now, using channel width, MCS index, and NSS we can determine the
* theoretical maximum data rate. We iterate through all possible
* combinations (width, MCS, NSS), saving the highest data rate we find.
*
* We could calculate a maximum data rate separately for TX/RX, but
* since this is only used for BSS ranking, the minimum between the
* two should be good enough.
*/
for (width = sizeof(vht_width_map[0]) - 1; width >= 0; width--) {
bool sgi = false;
if (!vht_width_map[channel_width_set][width])
continue;
/*
* Consolidate short GI support into a single boolean, dependent
* on the channel width for this iteration.
*/
switch (width) {
case OFDM_CHANNEL_WIDTH_20MHZ:
sgi = short_gi_20mhz;
break;
case OFDM_CHANNEL_WIDTH_40MHZ:
sgi = short_gi_40mhz;
break;
case OFDM_CHANNEL_WIDTH_80MHZ:
sgi = short_gi_80mhz;
break;
case OFDM_CHANNEL_WIDTH_160MHZ:
sgi = short_gi_160mhz;
break;
}
for (nss = minsize(rx_nss, tx_nss); nss > 0; nss--) {
/* NSS > 4 does not apply to 20/40MHz */
if (width <= OFDM_CHANNEL_WIDTH_40MHZ && nss > 4)
continue;
for (mcs = minsize(max_rx_mcs, max_tx_mcs);
mcs >= 0; mcs--) {
uint64_t drate;
if (!band_ofdm_rate(mcs, width, rssi,
nss, sgi, &drate))
continue;
if (drate > highest_rate)
highest_rate = drate;
/* Lower MCS index will only have lower rates */
goto next_chanwidth;
}
}
next_chanwidth: ; /* empty statement */
}
if (highest_rate == 0)
return -ENOTSUP;
*data_rate = highest_rate;
return 0;
}
static int ie_parse_vht_capability_from_data(const uint8_t *vht_ie,
size_t vht_len, const uint8_t *ht_ie,
size_t ht_len, int32_t rssi,
uint64_t *data_rate)
{
struct ie_tlv_iter vht_iter;
struct ie_tlv_iter ht_iter;
uint8_t tag;
ie_tlv_iter_init(&vht_iter, vht_ie, vht_len);
if (!ie_tlv_iter_next(&vht_iter))
return -EMSGSIZE;
tag = ie_tlv_iter_get_tag(&vht_iter);
if (tag != IE_TYPE_VHT_CAPABILITIES)
return -EPROTOTYPE;
ie_tlv_iter_init(&ht_iter, ht_ie, ht_len);
if (!ie_tlv_iter_next(&ht_iter))
return -EMSGSIZE;
tag = ie_tlv_iter_get_tag(&ht_iter);
if (tag != IE_TYPE_HT_CAPABILITIES)
return -EPROTOTYPE;
return ie_parse_vht_capability(&vht_iter, &ht_iter, rssi, data_rate);
}
/*
* Calculates the theoretical maximum data rates out of the provided
* supported rates IE, HT IE, and VHT IE. All 3 parsing functions are allowed
* to return -ENOTSUP, which indicates that a data rate was not found given
* the provided data. This is not fatal, it most likely means our RSSI was too
* low.
*/
int ie_parse_data_rates(const uint8_t *supp_rates_ie,
const uint8_t *ext_supp_rates_ie,
const uint8_t *ht_ie,
const uint8_t *vht_ie,
int32_t rssi,
uint64_t *data_rate)
{
int ret = -ENOTSUP;
uint64_t rate = 0;
/* An RSSI this low will not yield any rate results */
if (rssi < -82)
return -ENOTSUP;
if (ht_ie && vht_ie) {
ret = ie_parse_vht_capability_from_data(vht_ie, IE_LEN(vht_ie),
ht_ie, IE_LEN(ht_ie),
rssi, &rate);
if (ret == 0)
goto done;
}
if (ht_ie) {
ret = ie_parse_ht_capability_from_data(ht_ie, IE_LEN(ht_ie),
rssi, &rate);
if (ret == 0)
goto done;
}
if (supp_rates_ie || ext_supp_rates_ie) {
ret = ie_parse_supported_rates_from_data(supp_rates_ie,
ext_supp_rates_ie,
rssi, &rate);
if (ret == 0)
goto done;
}
return ret;
done:
*data_rate = rate;
return 0;
}
int ie_parse_mobility_domain(struct ie_tlv_iter *iter, uint16_t *mdid,
bool *ft_over_ds, bool *resource_req)
{

View File

@ -484,13 +484,6 @@ int ie_parse_bss_load_from_data(const uint8_t *data, uint8_t len,
uint8_t *out_channel_utilization,
uint16_t *out_admission_capacity);
int ie_parse_data_rates(const uint8_t *supp_rates_ie,
const uint8_t *ext_supp_rates_ie,
const uint8_t *ht_ie,
const uint8_t *vht_ie,
int32_t rssi,
uint64_t *data_rate);
int ie_parse_mobility_domain(struct ie_tlv_iter *iter, uint16_t *mdid,
bool *ft_over_ds, bool *resource_req);
int ie_parse_mobility_domain_from_data(const uint8_t *data, uint8_t len,