// SPDX-License-Identifier: GPL-2.0
/*
* This file contains helper code to handle channel
* settings and keeping track of what is possible at
* any point in time.
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2018-2026 Intel Corporation
*/
#include <linux/export.h>
#include <linux/bitfield.h>
#include <net/cfg80211.h>
#include "core.h"
#include "rdev-ops.h"
static bool cfg80211_valid_60g_freq(u32 freq)
{
return freq >= 58320 && freq <= 70200;
}
void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *chan,
enum nl80211_channel_type chan_type)
{
if (WARN_ON(!chan))
return;
*chandef = (struct cfg80211_chan_def) {
.chan = chan,
};
WARN_ON(chan->band == NL80211_BAND_60GHZ ||
chan->band == NL80211_BAND_S1GHZ);
switch (chan_type) {
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = chan->center_freq;
break;
case NL80211_CHAN_HT20:
chandef->width = NL80211_CHAN_WIDTH_20;
chandef->center_freq1 = chan->center_freq;
break;
case NL80211_CHAN_HT40PLUS:
chandef->width = NL80211_CHAN_WIDTH_40;
chandef->center_freq1 = chan->center_freq + 10;
break;
case NL80211_CHAN_HT40MINUS:
chandef->width = NL80211_CHAN_WIDTH_40;
chandef->center_freq1 = chan->center_freq - 10;
break;
default:
WARN_ON(1);
}
}
EXPORT_SYMBOL(cfg80211_chandef_create);
static u32 cfg80211_get_start_freq(const struct cfg80211_chan_def *chandef,
u32 cf)
{
u32 start_freq, center_freq, bandwidth;
center_freq = MHZ_TO_KHZ((cf == 1) ?
chandef->center_freq1 : chandef->center_freq2);
bandwidth = MHZ_TO_KHZ(cfg80211_chandef_get_width(chandef));
if (bandwidth <= MHZ_TO_KHZ(20))
start_freq = center_freq;
else
start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
return start_freq;
}
static u32 cfg80211_get_end_freq(const struct cfg80211_chan_def *chandef,
u32 cf)
{
u32 end_freq, center_freq, bandwidth;
center_freq = MHZ_TO_KHZ((cf == 1) ?
chandef->center_freq1 : chandef->center_freq2);
bandwidth = MHZ_TO_KHZ(cfg80211_chandef_get_width(chandef));
if (bandwidth <= MHZ_TO_KHZ(20))
end_freq = center_freq;
else
end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
return end_freq;
}
#define for_each_subchan(chandef, freq, cf) \
for (u32 punctured = chandef->punctured, \
cf = 1, freq = cfg80211_get_start_freq(chandef, cf); \
freq <= cfg80211_get_end_freq(chandef, cf); \
freq += MHZ_TO_KHZ(20), \
((cf == 1 && chandef->center_freq2 != 0 && \
freq > cfg80211_get_end_freq(chandef, cf)) ? \
(cf++, freq = cfg80211_get_start_freq(chandef, cf), \
punctured = 0) : (punctured >>= 1))) \
if (!
|