band: add oci_from_chandef

This adds a utility to convert a chandef obtained from the kernel into a
3 byte OCI element format containing the operating class, primary
  channel and secondary channel center frequency index.
This commit is contained in:
Denis Kenzior 2021-09-23 11:52:32 -05:00
parent 10f026748e
commit a2990443d2
2 changed files with 123 additions and 2 deletions

View File

@ -696,6 +696,100 @@ static int e4_channel_to_frequency(const struct operating_class_info *info,
return -EINVAL;
}
static int e4_frequency_to_channel(const struct operating_class_info *info,
uint32_t frequency)
{
return (frequency - info->starting_frequency) / 5;
}
static int e4_has_frequency(const struct operating_class_info *info,
uint32_t frequency)
{
unsigned int i;
unsigned int channel = e4_frequency_to_channel(info, frequency);
for (i = 0; info->channel_set[i] &&
i < L_ARRAY_SIZE(info->channel_set); i++) {
if (info->channel_set[i] != channel)
continue;
return 0;
}
return -ENOENT;
}
static int e4_has_ccfi(const struct operating_class_info *info,
uint32_t center_frequency)
{
unsigned int i;
unsigned int ccfi = e4_frequency_to_channel(info, center_frequency);
for (i = 0; info->center_frequencies[i] &&
i < L_ARRAY_SIZE(info->center_frequencies); i++) {
if (info->center_frequencies[i] != ccfi)
continue;
return 0;
}
return -ENOENT;
}
static int e4_class_matches(const struct operating_class_info *info,
const struct band_chandef *chandef)
{
int own_bandwidth = band_channel_info_get_bandwidth(chandef);
int r;
if (own_bandwidth < 0)
return own_bandwidth;
switch (chandef->channel_width) {
case BAND_CHANDEF_WIDTH_20NOHT:
case BAND_CHANDEF_WIDTH_20:
case BAND_CHANDEF_WIDTH_40:
if (own_bandwidth != info->channel_spacing)
return -ENOENT;
if (own_bandwidth == 40) {
uint32_t behavior;
if (chandef->center1_frequency > chandef->frequency)
behavior = PRIMARY_CHANNEL_LOWER;
else
behavior = PRIMARY_CHANNEL_UPPER;
if ((info->flags & behavior) != behavior)
return -ENOENT;
}
return e4_has_frequency(info, chandef->frequency);
case BAND_CHANDEF_WIDTH_80:
case BAND_CHANDEF_WIDTH_160:
if (info->flags & PLUS80)
return -ENOENT;
if (own_bandwidth != info->channel_spacing)
return -ENOENT;
return e4_has_ccfi(info, chandef->center1_frequency);
case BAND_CHANDEF_WIDTH_80P80:
if (!(info->flags & PLUS80))
return -ENOENT;
r = e4_has_ccfi(info, chandef->center1_frequency);
if (r < 0)
return r;
return e4_has_ccfi(info, chandef->center2_frequency);
default:
break;
}
return -ENOTSUP;
}
int oci_to_frequency(uint32_t operating_class, uint32_t channel)
{
const struct operating_class_info *info;
@ -794,8 +888,8 @@ int oci_verify(const uint8_t oci[static 3], const struct band_chandef *own)
if (!(info->flags & PLUS80))
return -EPERM;
freq_segment1_chan_num = (own->center2_frequency -
info->starting_frequency) / 5;
freq_segment1_chan_num =
e4_frequency_to_channel(info, own->center2_frequency);
if (freq_segment1_chan_num != oci[2])
return -EPERM;
@ -803,3 +897,29 @@ int oci_verify(const uint8_t oci[static 3], const struct band_chandef *own)
return 0;
}
int oci_from_chandef(const struct band_chandef *own, uint8_t oci[static 3])
{
unsigned int i;
for (i = 0; i < L_ARRAY_SIZE(e4_operating_classes); i++) {
const struct operating_class_info *info =
&e4_operating_classes[i];
if (e4_class_matches(info, own) < 0)
continue;
oci[0] = info->operating_class;
oci[1] = e4_frequency_to_channel(info, own->frequency);
if (own->center2_frequency)
oci[2] = e4_frequency_to_channel(info,
own->center2_frequency);
else
oci[2] = 0;
return 0;
}
return -ENOENT;
}

View File

@ -75,3 +75,4 @@ int band_estimate_nonht_rate(const struct band *band,
int oci_to_frequency(uint32_t operating_class, uint32_t channel);
int oci_verify(const uint8_t oci[static 3], const struct band_chandef *own);
int oci_from_chandef(const struct band_chandef *own, uint8_t oci[static 3]);