mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
nl80211: support setting S1G channels
S1G channels have a single width defined per frequency, so derive it from the channel flags with ieee80211_s1g_channel_width(). Also support setting an S1G channel where control frequency may differ from operating, and add some basic validation to ensure the control channel is with the operating. Signed-off-by: Thomas Pedersen <thomas@adapt-ip.com> Link: https://lore.kernel.org/r/20200908190323.15814-6-thomas@adapt-ip.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
1d47f1198d
commit
11b34737b1
3 changed files with 115 additions and 52 deletions
|
@ -5294,6 +5294,16 @@ ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
|
||||||
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
|
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_s1g_channel_width - get allowed channel width from @chan
|
||||||
|
*
|
||||||
|
* Only allowed for band NL80211_BAND_S1GHZ
|
||||||
|
* @chan: channel
|
||||||
|
* Return: The allowed channel width for this center_freq
|
||||||
|
*/
|
||||||
|
enum nl80211_chan_width
|
||||||
|
ieee80211_s1g_channel_width(const struct ieee80211_channel *chan);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_channel_to_freq_khz - convert channel number to frequency
|
* ieee80211_channel_to_freq_khz - convert channel number to frequency
|
||||||
* @chan: channel number
|
* @chan: channel number
|
||||||
|
|
|
@ -141,9 +141,62 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
|
||||||
|
{
|
||||||
|
int mhz;
|
||||||
|
|
||||||
|
switch (chan_width) {
|
||||||
|
case NL80211_CHAN_WIDTH_1:
|
||||||
|
mhz = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_2:
|
||||||
|
mhz = 2;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_4:
|
||||||
|
mhz = 4;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_8:
|
||||||
|
mhz = 8;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_16:
|
||||||
|
mhz = 16;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_5:
|
||||||
|
mhz = 5;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_10:
|
||||||
|
mhz = 10;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_20:
|
||||||
|
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||||
|
mhz = 20;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_40:
|
||||||
|
mhz = 40;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
case NL80211_CHAN_WIDTH_80:
|
||||||
|
mhz = 80;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_160:
|
||||||
|
mhz = 160;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return mhz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
|
||||||
|
{
|
||||||
|
return nl80211_chan_width_to_mhz(c->width);
|
||||||
|
}
|
||||||
|
|
||||||
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
||||||
{
|
{
|
||||||
u32 control_freq;
|
u32 control_freq, oper_freq;
|
||||||
|
int oper_width, control_width;
|
||||||
|
|
||||||
if (!chandef->chan)
|
if (!chandef->chan)
|
||||||
return false;
|
return false;
|
||||||
|
@ -155,10 +208,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
||||||
|
|
||||||
switch (chandef->width) {
|
switch (chandef->width) {
|
||||||
case NL80211_CHAN_WIDTH_1:
|
case NL80211_CHAN_WIDTH_1:
|
||||||
case NL80211_CHAN_WIDTH_2:
|
|
||||||
case NL80211_CHAN_WIDTH_4:
|
|
||||||
case NL80211_CHAN_WIDTH_8:
|
|
||||||
case NL80211_CHAN_WIDTH_16:
|
|
||||||
case NL80211_CHAN_WIDTH_5:
|
case NL80211_CHAN_WIDTH_5:
|
||||||
case NL80211_CHAN_WIDTH_10:
|
case NL80211_CHAN_WIDTH_10:
|
||||||
case NL80211_CHAN_WIDTH_20:
|
case NL80211_CHAN_WIDTH_20:
|
||||||
|
@ -169,6 +218,30 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
||||||
if (chandef->center_freq2)
|
if (chandef->center_freq2)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_2:
|
||||||
|
case NL80211_CHAN_WIDTH_4:
|
||||||
|
case NL80211_CHAN_WIDTH_8:
|
||||||
|
case NL80211_CHAN_WIDTH_16:
|
||||||
|
control_freq = ieee80211_channel_to_khz(chandef->chan);
|
||||||
|
oper_freq = ieee80211_chandef_to_khz(chandef);
|
||||||
|
control_width = nl80211_chan_width_to_mhz(
|
||||||
|
ieee80211_s1g_channel_width(
|
||||||
|
chandef->chan));
|
||||||
|
oper_width = cfg80211_chandef_get_width(chandef);
|
||||||
|
|
||||||
|
if (oper_width < 0 || control_width < 0)
|
||||||
|
return false;
|
||||||
|
if (chandef->center_freq2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (control_freq + MHZ_TO_KHZ(control_width) / 2 >
|
||||||
|
oper_freq + MHZ_TO_KHZ(oper_width) / 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (control_freq - MHZ_TO_KHZ(control_width) / 2 <
|
||||||
|
oper_freq - MHZ_TO_KHZ(oper_width) / 2)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case NL80211_CHAN_WIDTH_40:
|
case NL80211_CHAN_WIDTH_40:
|
||||||
if (chandef->center_freq1 != control_freq + 10 &&
|
if (chandef->center_freq1 != control_freq + 10 &&
|
||||||
chandef->center_freq1 != control_freq - 10)
|
chandef->center_freq1 != control_freq - 10)
|
||||||
|
@ -264,53 +337,6 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
|
|
||||||
{
|
|
||||||
int width;
|
|
||||||
|
|
||||||
switch (c->width) {
|
|
||||||
case NL80211_CHAN_WIDTH_1:
|
|
||||||
width = 1;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_2:
|
|
||||||
width = 2;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_4:
|
|
||||||
width = 4;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_8:
|
|
||||||
width = 8;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_16:
|
|
||||||
width = 16;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_5:
|
|
||||||
width = 5;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_10:
|
|
||||||
width = 10;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_20:
|
|
||||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
|
||||||
width = 20;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_40:
|
|
||||||
width = 40;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_80P80:
|
|
||||||
case NL80211_CHAN_WIDTH_80:
|
|
||||||
width = 80;
|
|
||||||
break;
|
|
||||||
case NL80211_CHAN_WIDTH_160:
|
|
||||||
width = 160;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct cfg80211_chan_def *
|
const struct cfg80211_chan_def *
|
||||||
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
|
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
|
||||||
const struct cfg80211_chan_def *c2)
|
const struct cfg80211_chan_def *c2)
|
||||||
|
|
|
@ -111,6 +111,33 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
|
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
|
||||||
|
|
||||||
|
enum nl80211_chan_width
|
||||||
|
ieee80211_s1g_channel_width(const struct ieee80211_channel *chan)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!chan || chan->band != NL80211_BAND_S1GHZ))
|
||||||
|
return NL80211_CHAN_WIDTH_20_NOHT;
|
||||||
|
|
||||||
|
/*S1G defines a single allowed channel width per channel.
|
||||||
|
* Extract that width here.
|
||||||
|
*/
|
||||||
|
if (chan->flags & IEEE80211_CHAN_1MHZ)
|
||||||
|
return NL80211_CHAN_WIDTH_1;
|
||||||
|
else if (chan->flags & IEEE80211_CHAN_2MHZ)
|
||||||
|
return NL80211_CHAN_WIDTH_2;
|
||||||
|
else if (chan->flags & IEEE80211_CHAN_4MHZ)
|
||||||
|
return NL80211_CHAN_WIDTH_4;
|
||||||
|
else if (chan->flags & IEEE80211_CHAN_8MHZ)
|
||||||
|
return NL80211_CHAN_WIDTH_8;
|
||||||
|
else if (chan->flags & IEEE80211_CHAN_16MHZ)
|
||||||
|
return NL80211_CHAN_WIDTH_16;
|
||||||
|
|
||||||
|
pr_err("unknown channel width for channel at %dKHz?\n",
|
||||||
|
ieee80211_channel_to_khz(chan));
|
||||||
|
|
||||||
|
return NL80211_CHAN_WIDTH_1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_s1g_channel_width);
|
||||||
|
|
||||||
int ieee80211_freq_khz_to_channel(u32 freq)
|
int ieee80211_freq_khz_to_channel(u32 freq)
|
||||||
{
|
{
|
||||||
/* TODO: just handle MHz for now */
|
/* TODO: just handle MHz for now */
|
||||||
|
|
Loading…
Reference in a new issue