Hello,
This patchset prepares for adding 802.11ah (S1G) support.
S1G channels, at least in the US, may be centered on a sub-MHz
frequency. The current channel structures and nl80211 APIs expect
frequencies in units of MHz. To extend the existing functionality and
APIs while reducing churn and breakage, we add a KHz offset where
needed. This also has the advantage that the KHz offset can be ignored
at will (legacy drivers).
Some cfg80211 and nl80211 internals have been converted to handle units
of KHz, which is not unprecedented (net/wireless/reg.c), and the
collateral damage is localized.
One thing which is still unclear is backward compatibility in nl80211.
If a frequency offset is supplied to an older kernel, it'll just
silently fail to do the right thing. Likewise, these patches will accept
a frequency offset to eg. NL80211_CMD_JOIN_MESH, but not handle it in
mac80211. For this case is it sufficient to return an error?
The hostap hwsim tests are still passing on par with HEAD. Before these
become PATCH we'd like to add some tests exercising the new nl80211
attributes, but it seems difficult without pulling in the full S1G
patchset. Maybe we'll hack up hwsim + regulatory to use the S1G band for
regular wifi tests. Suggestions here are welcome.
Thanks for looking.
Thomas Pedersen (7):
ieee80211: share 802.11 unit conversion helpers
cfg80211: express channels with a KHz component
mac80211: handle channel frequency offset
mac80211: add freq_offset to RX status
cfg80211: report frequency in KHz for management RX
nl80211: add KHz frequency offset for most wifi commands
nl80211: accept scan frequencies in KHz
drivers/net/wireless/ath/ath6kl/wmi.c | 5 +-
drivers/net/wireless/ath/wil6210/wmi.c | 3 +-
.../broadcom/brcm80211/brcmfmac/p2p.c | 6 +-
drivers/net/wireless/marvell/mwifiex/util.c | 3 +-
drivers/staging/wilc1000/cfg80211.c | 2 +-
include/linux/ieee80211.h | 11 +++
include/net/cfg80211.h | 70 ++++++++++++-
include/net/mac80211.h | 10 +-
include/net/regulatory.h | 7 --
include/uapi/linux/nl80211.h | 51 +++++++---
net/mac80211/chan.c | 1 +
net/mac80211/main.c | 8 +-
net/mac80211/mlme.c | 22 +++--
net/mac80211/rx.c | 7 +-
net/mac80211/scan.c | 4 +-
net/mac80211/trace.h | 41 ++++++--
net/wireless/chan.c | 68 +++++++------
net/wireless/nl80211.c | 97 ++++++++++++++-----
net/wireless/reg.c | 40 ++++----
net/wireless/scan.c | 4 +-
net/wireless/trace.h | 21 +++-
net/wireless/util.c | 72 ++++++++++++--
22 files changed, 406 insertions(+), 147 deletions(-)
--
2.20.1
cfg80211_chan_def and ieee80211_channel recently gained a
frequency offset component. Handle this where it makes
sense (potentially required by S1G channels), ie. ignore
for mesh, ibss, HT/VHT specific stuff, TDLS, etc.
Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/chan.c | 1 +
net/mac80211/main.c | 8 +++++---
net/mac80211/mlme.c | 16 ++++++++++++----
net/mac80211/scan.c | 1 +
net/mac80211/trace.h | 41 +++++++++++++++++++++++++++++++++--------
5 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 9c94baaf693c..e6e192f53e4e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -533,6 +533,7 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
struct cfg80211_chan_def *chandef = &local->_oper_chandef;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = chandef->chan->center_freq;
+ chandef->freq1_offset = chandef->chan->freq_offset;
chandef->center_freq2 = 0;
/* NOTE: Disabling radar is only valid here for
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8345926193de..3ee47dc2584b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -104,13 +104,15 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
chandef.chan = local->tmp_channel;
chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
chandef.center_freq1 = chandef.chan->center_freq;
+ chandef.freq1_offset = chandef.chan->freq_offset;
} else
chandef = local->_oper_chandef;
WARN(!cfg80211_chandef_valid(&chandef),
- "control:%d MHz width:%d center: %d/%d MHz",
- chandef.chan->center_freq, chandef.width,
- chandef.center_freq1, chandef.center_freq2);
+ "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz",
+ chandef.chan->center_freq, chandef.chan->freq_offset,
+ chandef.width, chandef.center_freq1, chandef.freq1_offset,
+ chandef.center_freq2);
if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef))
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 16d75da0996a..4eebee49bb7d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -162,6 +162,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->chan = channel;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = channel->center_freq;
+ chandef->freq1_offset = channel->freq_offset;
if (!ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT |
@@ -396,9 +397,12 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
return 0;
sdata_info(sdata,
- "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n",
- ifmgd->bssid, chandef.chan->center_freq, chandef.width,
- chandef.center_freq1, chandef.center_freq2);
+ "AP %pM changed bandwidth, new config is %d.%03d MHz, "
+ "width %d (%d.%03d/%d MHz)\n",
+ ifmgd->bssid, chandef.chan->center_freq,
+ chandef.chan->freq_offset, chandef.width,
+ chandef.center_freq1, chandef.freq1_offset,
+ chandef.center_freq2);
if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
@@ -1364,10 +1368,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata,
- "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+ "AP %pM switches to unsupported channel "
+ "(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), "
+ "disconnecting\n",
ifmgd->associated->bssid,
csa_ie.chandef.chan->center_freq,
+ csa_ie.chandef.chan->freq_offset,
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
+ csa_ie.chandef.freq1_offset,
csa_ie.chandef.center_freq2);
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index fdac8192a519..4d14118dddca 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -896,6 +896,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
local->scan_chandef.chan = chan;
local->scan_chandef.center_freq1 = chan->center_freq;
+ local->scan_chandef.freq1_offset = chan->freq_offset;
local->scan_chandef.center_freq2 = 0;
switch (scan_req->scan_width) {
case NL80211_BSS_CHAN_WIDTH_5:
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 427f51a0a994..1b4709694d2a 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -37,32 +37,42 @@
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
#define CHANDEF_ENTRY __field(u32, control_freq) \
+ __field(u32, freq_offset) \
__field(u32, chan_width) \
__field(u32, center_freq1) \
+ __field(u32, freq1_offset) \
__field(u32, center_freq2)
#define CHANDEF_ASSIGN(c) \
__entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0; \
+ __entry->freq_offset = (c) ? ((c)->chan ? (c)->chan->freq_offset : 0) : 0; \
__entry->chan_width = (c) ? (c)->width : 0; \
__entry->center_freq1 = (c) ? (c)->center_freq1 : 0; \
+ __entry->freq1_offset = (c) ? (c)->freq1_offset : 0; \
__entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
-#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
-#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
- __entry->center_freq1, __entry->center_freq2
+#define CHANDEF_PR_FMT " control:%d.%03d MHz width:%d center: %d.%03d/%d MHz"
+#define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \
+ __entry->center_freq1, __entry->freq1_offset, __entry->center_freq2
#define MIN_CHANDEF_ENTRY \
__field(u32, min_control_freq) \
+ __field(u32, min_freq_offset) \
__field(u32, min_chan_width) \
__field(u32, min_center_freq1) \
+ __field(u32, min_freq1_offset) \
__field(u32, min_center_freq2)
#define MIN_CHANDEF_ASSIGN(c) \
__entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
+ __entry->min_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0; \
__entry->min_chan_width = (c)->width; \
__entry->min_center_freq1 = (c)->center_freq1; \
+ __entry->freq1_offset = (c)->freq1_offset; \
__entry->min_center_freq2 = (c)->center_freq2;
-#define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
-#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \
- __entry->min_center_freq1, __entry->min_center_freq2
+#define MIN_CHANDEF_PR_FMT " min_control:%d.%03d MHz min_width:%d min_center: %d.%03d/%d MHz"
+#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \
+ __entry->min_chan_width, \
+ __entry->min_center_freq1, __entry->min_freq1_offset, \
+ __entry->min_center_freq2
#define CHANCTX_ENTRY CHANDEF_ENTRY \
MIN_CHANDEF_ENTRY \
@@ -412,6 +422,7 @@ TRACE_EVENT(drv_bss_info_changed,
__field(s32, cqm_rssi_hyst)
__field(u32, channel_width)
__field(u32, channel_cfreq1)
+ __field(u32, channel_cfreq1_offset)
__dynamic_array(u32, arp_addr_list,
info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
IEEE80211_BSS_ARP_ADDR_LIST_LEN :
@@ -452,6 +463,7 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
__entry->channel_width = info->chandef.width;
__entry->channel_cfreq1 = info->chandef.center_freq1;
+ __entry->channel_cfreq1_offset = info->chandef.freq1_offset;
__entry->arp_addr_cnt = info->arp_addr_cnt;
memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
@@ -1223,6 +1235,7 @@ TRACE_EVENT(drv_remain_on_channel,
LOCAL_ENTRY
VIF_ENTRY
__field(int, center_freq)
+ __field(int, freq_offset)
__field(unsigned int, duration)
__field(u32, type)
),
@@ -1231,14 +1244,16 @@ TRACE_EVENT(drv_remain_on_channel,
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->center_freq = chan->center_freq;
+ __entry->freq_offset = chan->freq_offset;
__entry->duration = duration;
__entry->type = type;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
+ LOCAL_PR_FMT VIF_PR_FMT " freq:%d.%03dMHz duration:%dms type=%d",
LOCAL_PR_ARG, VIF_PR_ARG,
- __entry->center_freq, __entry->duration, __entry->type
+ __entry->center_freq, __entry->freq_offset,
+ __entry->duration, __entry->type
)
);
@@ -1546,8 +1561,10 @@ struct trace_vif_entry {
struct trace_chandef_entry {
u32 control_freq;
+ u32 freq_offset;
u32 chan_width;
u32 center_freq1;
+ u32 freq1_offset;
u32 center_freq2;
} __packed;
@@ -1597,18 +1614,26 @@ TRACE_EVENT(drv_switch_vif_chanctx,
sizeof(local_vifs[i].vif.vif_name));
SWITCH_ENTRY_ASSIGN(old_chandef.control_freq,
old_ctx->def.chan->center_freq);
+ SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset,
+ old_ctx->def.chan->freq_offset);
SWITCH_ENTRY_ASSIGN(old_chandef.chan_width,
old_ctx->def.width);
SWITCH_ENTRY_ASSIGN(old_chandef.center_freq1,
old_ctx->def.center_freq1);
+ SWITCH_ENTRY_ASSIGN(old_chandef.freq1_offset,
+ old_ctx->def.freq1_offset);
SWITCH_ENTRY_ASSIGN(old_chandef.center_freq2,
old_ctx->def.center_freq2);
SWITCH_ENTRY_ASSIGN(new_chandef.control_freq,
new_ctx->def.chan->center_freq);
+ SWITCH_ENTRY_ASSIGN(new_chandef.freq_offset,
+ new_ctx->def.chan->freq_offset);
SWITCH_ENTRY_ASSIGN(new_chandef.chan_width,
new_ctx->def.width);
SWITCH_ENTRY_ASSIGN(new_chandef.center_freq1,
new_ctx->def.center_freq1);
+ SWITCH_ENTRY_ASSIGN(new_chandef.freq1_offset,
+ new_ctx->def.freq1_offset);
SWITCH_ENTRY_ASSIGN(new_chandef.center_freq2,
new_ctx->def.center_freq2);
}
--
2.20.1
Some bands (S1G) define channels centered on a non-integer
MHz. Give ieee80211_channel and cfg80211_chan_def a
freq_offset component where the final frequency can be
expressed as:
MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
Also provide some helper functions to do the frequency
conversion and test for equality.
Retain the existing interface to frequency and channel
conversion helpers, and expose new ones which handle
frequencies in units of KHz.
Some internal functions (net/wireless/chan.c) pass around
a frequency value. Convert these to units of KHz.
mesh, ibss, wext, etc. are currently ignored.
Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/cfg80211.h | 66 ++++++++++++++++++++++++++++++++++++--
net/wireless/chan.c | 68 +++++++++++++++++++++------------------
net/wireless/reg.c | 40 ++++++++++++-----------
net/wireless/scan.c | 4 +--
net/wireless/trace.h | 21 +++++++++---
net/wireless/util.c | 72 ++++++++++++++++++++++++++++++++++++------
6 files changed, 202 insertions(+), 69 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index c78bd4ff9e33..000721915f21 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -128,6 +128,7 @@ enum ieee80211_channel_flags {
* with cfg80211.
*
* @center_freq: center frequency in MHz
+ * @freq_offset: offset from @center_freq, in KHz
* @hw_value: hardware-specific value for the channel
* @flags: channel flags from &enum ieee80211_channel_flags.
* @orig_flags: channel flags at registration time, used by regulatory
@@ -149,6 +150,7 @@ enum ieee80211_channel_flags {
struct ieee80211_channel {
enum nl80211_band band;
u32 center_freq;
+ u16 freq_offset;
u16 hw_value;
u32 flags;
int max_antenna_gain;
@@ -617,6 +619,7 @@ struct key_params {
* If edmg is requested (i.e. the .channels member is non-zero),
* chan will define the primary channel and all other
* parameters are ignored.
+ * @freq1_offset: offset from @center_freq1, in KHz
*/
struct cfg80211_chan_def {
struct ieee80211_channel *chan;
@@ -624,6 +627,7 @@ struct cfg80211_chan_def {
u32 center_freq1;
u32 center_freq2;
struct ieee80211_edmg edmg;
+ u16 freq1_offset;
};
/**
@@ -713,6 +717,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
return (chandef1->chan == chandef2->chan &&
chandef1->width == chandef2->width &&
chandef1->center_freq1 == chandef2->center_freq1 &&
+ chandef1->freq1_offset == chandef2->freq1_offset &&
chandef1->center_freq2 == chandef2->center_freq2);
}
@@ -5145,6 +5150,28 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
* cfg80211 offers a number of utility functions that can be useful.
*/
+/**
+ * ieee80211_channel_equal - compare two struct ieee80211_channel
+ *
+ * @a: 1st struct ieee80211_channel
+ * @b: 2nd struct ieee80211_channel
+ * Return: true if center frequency of @a == @b
+ */
+static inline bool
+ieee80211_channel_equal(struct ieee80211_channel *a,
+ struct ieee80211_channel *b)
+{
+ return (a->center_freq == b->center_freq &&
+ a->freq_offset == b->freq_offset);
+}
+
+/**
+ * ieee80211_channel_to_khz - convert ieee80211_channel to frequency in KHz
+ * @chan: struct ieee80211_channel to convert
+ * Return: The corresponding frequency (in KHz)
+ */
+u32 ieee80211_channel_to_khz(const struct ieee80211_channel *chan);
+
/**
* ieee80211_channel_to_frequency - convert channel number to frequency
* @chan: channel number
@@ -5153,23 +5180,47 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
*/
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
+/**
+ * ieee80211_channel_to_freq_khz - convert channel number to frequency
+ * @chan: channel number
+ * @band: band, necessary due to channel number overlap
+ * Return: The corresponding frequency (in KHz), or 0 if the conversion failed.
+ */
+u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band);
+
/**
* ieee80211_frequency_to_channel - convert frequency to channel number
- * @freq: center frequency
+ * @freq: center frequency in MHz
* Return: The corresponding channel, or 0 if the conversion failed.
*/
int ieee80211_frequency_to_channel(int freq);
+/**
+ * ieee80211_freq_khz_to_channel - convert frequency to channel number
+ * @freq: center frequency in KHz
+ * Return: The corresponding channel, or 0 if the conversion failed.
+ */
+int ieee80211_freq_khz_to_channel(u32 freq);
+
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
*
* @wiphy: the struct wiphy to get the channel for
- * @freq: the center frequency of the channel
- *
+ * @freq: the center frequency (in MHz) of the channel
* Return: The channel struct from @wiphy at @freq.
*/
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
+/**
+ * ieee80211_get_channel_khz - get channel struct from wiphy for specified
+ * frequency
+ * @wiphy: the struct wiphy to get the channel for
+ * @freq: the center frequency (in KHz) of the channel
+ * Return: The channel struct from @wiphy at @freq.
+ */
+struct ieee80211_channel *
+ieee80211_get_channel_khz(struct wiphy *wiphy, u32 freq);
+
/**
* ieee80211_get_response_rate - get basic rate for a given rate
*
@@ -7192,6 +7243,15 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
u8 *op_class);
+/**
+ * ieee80211_chandef_to_khz - convert chandef to frequency in KHz
+ *
+ * @chandef: the chandef to convert
+ *
+ * Returns the center frequency of chandef (1st segment) in KHz.
+ */
+u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef);
+
/*
* cfg80211_tdls_oper_request - request userspace to perform TDLS operation
* @dev: the device on which the operation is requested
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index fcac5c6366e1..6f1fbd25c8ff 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -27,6 +27,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
return;
chandef->chan = chan;
+ chandef->freq1_offset = chan->freq_offset;
chandef->center_freq2 = 0;
chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0;
@@ -153,7 +154,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
- if (chandef->center_freq1 != control_freq)
+ if (ieee80211_chandef_to_khz(chandef) !=
+ ieee80211_channel_to_khz(chandef->chan))
return false;
if (chandef->center_freq2)
return false;
@@ -386,10 +388,11 @@ static u32 cfg80211_get_start_freq(u32 center_freq,
{
u32 start_freq;
- if (bandwidth <= 20)
+ bandwidth = MHZ_TO_KHZ(bandwidth);
+ if (bandwidth <= MHZ_TO_KHZ(20))
start_freq = center_freq;
else
- start_freq = center_freq - bandwidth/2 + 10;
+ start_freq = center_freq - bandwidth/2 + MHZ_TO_KHZ(10);
return start_freq;
}
@@ -399,10 +402,11 @@ static u32 cfg80211_get_end_freq(u32 center_freq,
{
u32 end_freq;
- if (bandwidth <= 20)
+ bandwidth = MHZ_TO_KHZ(bandwidth);
+ if (bandwidth <= MHZ_TO_KHZ(20))
end_freq = center_freq;
else
- end_freq = center_freq + bandwidth/2 - 10;
+ end_freq = center_freq + bandwidth/2 - MHZ_TO_KHZ(10);
return end_freq;
}
@@ -417,8 +421,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
- for (freq = start_freq; freq <= end_freq; freq += 20) {
- c = ieee80211_get_channel(wiphy, freq);
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return -EINVAL;
@@ -449,8 +453,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return -EINVAL;
ret = cfg80211_get_chans_dfs_required(wiphy,
- chandef->center_freq1,
- width);
+ ieee80211_chandef_to_khz(chandef),
+ width);
if (ret < 0)
return ret;
else if (ret > 0)
@@ -460,8 +464,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return 0;
ret = cfg80211_get_chans_dfs_required(wiphy,
- chandef->center_freq2,
- width);
+ MHZ_TO_KHZ(chandef->center_freq2),
+ width);
if (ret < 0)
return ret;
else if (ret > 0)
@@ -503,8 +507,8 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
* DFS_AVAILABLE). Return number of usable channels
* (require CAC). Allow DFS and non-DFS channel mix.
*/
- for (freq = start_freq; freq <= end_freq; freq += 20) {
- c = ieee80211_get_channel(wiphy, freq);
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return -EINVAL;
@@ -536,8 +540,9 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
if (width < 0)
return false;
- r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
- width);
+ r1 = cfg80211_get_chans_dfs_usable(wiphy,
+ MHZ_TO_KHZ(chandef->center_freq1),
+ width);
if (r1 < 0)
return false;
@@ -546,8 +551,8 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r2 = cfg80211_get_chans_dfs_usable(wiphy,
- chandef->center_freq2,
- width);
+ MHZ_TO_KHZ(chandef->center_freq2),
+ width);
if (r2 < 0)
return false;
break;
@@ -694,8 +699,8 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
* If any channel in between is disabled or has not
* had gone through CAC return false
*/
- for (freq = start_freq; freq <= end_freq; freq += 20) {
- c = ieee80211_get_channel(wiphy, freq);
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return false;
@@ -724,7 +729,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
if (width < 0)
return false;
- r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
+ r = cfg80211_get_chans_dfs_available(wiphy,
+ MHZ_TO_KHZ(chandef->center_freq1),
width);
/* If any of channels unavailable for cf1 just return */
@@ -735,8 +741,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r = cfg80211_get_chans_dfs_available(wiphy,
- chandef->center_freq2,
- width);
+ MHZ_TO_KHZ(chandef->center_freq2),
+ width);
break;
default:
WARN_ON(chandef->center_freq2);
@@ -757,8 +763,8 @@ static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
- for (freq = start_freq; freq <= end_freq; freq += 20) {
- c = ieee80211_get_channel(wiphy, freq);
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return 0;
@@ -790,14 +796,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
return 0;
t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
- chandef->center_freq1,
+ MHZ_TO_KHZ(chandef->center_freq1),
width);
if (!chandef->center_freq2)
return t1;
t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
- chandef->center_freq2,
+ MHZ_TO_KHZ(chandef->center_freq2),
width);
return max(t1, t2);
@@ -813,8 +819,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
- for (freq = start_freq; freq <= end_freq; freq += 20) {
- c = ieee80211_get_channel(wiphy, freq);
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
if (!c || c->flags & prohibited_flags)
return false;
}
@@ -976,13 +982,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
- if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
+ if (!cfg80211_secondary_chans_ok(wiphy,
+ ieee80211_chandef_to_khz(chandef),
width, prohibited_flags))
return false;
if (!chandef->center_freq2)
return true;
- return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
+ return cfg80211_secondary_chans_ok(wiphy,
+ MHZ_TO_KHZ(chandef->center_freq2),
width, prohibited_flags);
}
EXPORT_SYMBOL(cfg80211_chandef_usable);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index d476d4da0d09..0d74a31ef0ab 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1658,22 +1658,23 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
const struct ieee80211_channel *chan)
{
const struct ieee80211_freq_range *freq_range = NULL;
- u32 max_bandwidth_khz, bw_flags = 0;
+ u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
freq_range = ®_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz;
+ center_freq_khz = ieee80211_channel_to_khz(chan);
/* Check if auto calculation requested */
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
/* If we get a reg_rule we can assume that at least 5Mhz fit */
if (!cfg80211_does_bw_fit_range(freq_range,
- MHZ_TO_KHZ(chan->center_freq),
+ center_freq_khz,
MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!cfg80211_does_bw_fit_range(freq_range,
- MHZ_TO_KHZ(chan->center_freq),
+ center_freq_khz,
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
@@ -1710,7 +1711,7 @@ static void handle_channel(struct wiphy *wiphy,
flags = chan->orig_flags;
- reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
+ reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
if (IS_ERR(reg_rule)) {
/*
* We will disable all channels that do not match our
@@ -1729,13 +1730,13 @@ static void handle_channel(struct wiphy *wiphy,
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
request_wiphy && request_wiphy == wiphy &&
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
- pr_debug("Disabling freq %d MHz for good\n",
- chan->center_freq);
+ pr_debug("Disabling freq %d.%03d MHz for good\n",
+ chan->center_freq, chan->freq_offset);
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
chan->flags = chan->orig_flags;
} else {
- pr_debug("Disabling freq %d MHz\n",
- chan->center_freq);
+ pr_debug("Disabling freq %d.%03d MHz\n",
+ chan->center_freq, chan->freq_offset);
chan->flags |= IEEE80211_CHAN_DISABLED;
}
return;
@@ -1936,7 +1937,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
sband = wiphy->bands[reg_beacon->chan.band];
chan = &sband->channels[chan_idx];
- if (likely(chan->center_freq != reg_beacon->chan.center_freq))
+ if (likely(!ieee80211_channel_equal(chan, ®_beacon->chan)))
return;
if (chan->beacon_found)
@@ -2269,18 +2270,18 @@ static void handle_channel_custom(struct wiphy *wiphy,
u32 bw_flags = 0;
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
- u32 bw;
+ u32 bw, center_freq_khz;
+ center_freq_khz = ieee80211_channel_to_khz(chan);
for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
- reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq),
- regd, bw);
+ reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
if (!IS_ERR(reg_rule))
break;
}
if (IS_ERR_OR_NULL(reg_rule)) {
- pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
- chan->center_freq);
+ pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
+ chan->center_freq, chan->freq_offset);
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
chan->flags |= IEEE80211_CHAN_DISABLED;
} else {
@@ -3337,8 +3338,8 @@ static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
struct reg_beacon *pending_beacon;
list_for_each_entry(pending_beacon, ®_pending_beacons, list)
- if (beacon_chan->center_freq ==
- pending_beacon->chan.center_freq)
+ if (ieee80211_channel_equal(beacon_chan,
+ &pending_beacon->chan))
return true;
return false;
}
@@ -3367,9 +3368,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
if (!reg_beacon)
return -ENOMEM;
- pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
- beacon_chan->center_freq,
- ieee80211_frequency_to_channel(beacon_chan->center_freq),
+ pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
+ beacon_chan->center_freq, beacon_chan->freq_offset,
+ ieee80211_freq_khz_to_channel(
+ ieee80211_channel_to_khz(beacon_chan)),
wiphy_name(wiphy));
memcpy(®_beacon->chan, beacon_chan,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 4000382aef48..74ea4cfb39fb 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1322,8 +1322,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
return channel;
}
- freq = ieee80211_channel_to_frequency(channel_number, channel->band);
- alt_channel = ieee80211_get_channel(wiphy, freq);
+ freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
+ alt_channel = ieee80211_get_channel_khz(wiphy, freq);
if (!alt_channel) {
if (channel->band == NL80211_BAND_2GHZ) {
/*
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 839df54cee21..74647f239581 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -112,24 +112,29 @@
} while (0)
#define CHAN_ENTRY __field(enum nl80211_band, band) \
- __field(u32, center_freq)
+ __field(u32, center_freq) \
+ __field(u16, freq_offset)
#define CHAN_ASSIGN(chan) \
do { \
if (chan) { \
__entry->band = chan->band; \
__entry->center_freq = chan->center_freq; \
+ __entry->freq_offset = chan->freq_offset; \
} else { \
__entry->band = 0; \
__entry->center_freq = 0; \
+ __entry->freq_offset = 0; \
} \
} while (0)
-#define CHAN_PR_FMT "band: %d, freq: %u"
-#define CHAN_PR_ARG __entry->band, __entry->center_freq
+#define CHAN_PR_FMT "band: %d, freq: %u.%03u"
+#define CHAN_PR_ARG __entry->band, __entry->center_freq, __entry->freq_offset
#define CHAN_DEF_ENTRY __field(enum nl80211_band, band) \
__field(u32, control_freq) \
+ __field(u32, freq_offset) \
__field(u32, width) \
__field(u32, center_freq1) \
+ __field(u32, freq1_offset) \
__field(u32, center_freq2)
#define CHAN_DEF_ASSIGN(chandef) \
do { \
@@ -137,21 +142,27 @@
__entry->band = (chandef)->chan->band; \
__entry->control_freq = \
(chandef)->chan->center_freq; \
+ __entry->freq_offset = \
+ (chandef)->chan->freq_offset; \
__entry->width = (chandef)->width; \
__entry->center_freq1 = (chandef)->center_freq1;\
+ __entry->freq1_offset = (chandef)->freq1_offset;\
__entry->center_freq2 = (chandef)->center_freq2;\
} else { \
__entry->band = 0; \
__entry->control_freq = 0; \
+ __entry->freq_offset = 0; \
__entry->width = 0; \
__entry->center_freq1 = 0; \
+ __entry->freq1_offset = 0; \
__entry->center_freq2 = 0; \
} \
} while (0)
#define CHAN_DEF_PR_FMT \
- "band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
+ "band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u"
#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
- __entry->width, __entry->center_freq1, \
+ __entry->freq_offset, __entry->width, \
+ __entry->center_freq1, __entry->freq1_offset, \
__entry->center_freq2
#define SINFO_ENTRY __field(int, generation) \
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6590efbbcbb9..6e73ef51b39e 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -72,7 +72,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
}
EXPORT_SYMBOL(ieee80211_mandatory_rates);
-int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
+static u32 __ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
{
/* see 802.11 17.3.8.3.2 and Annex J
* there are overlapping channel numbers in 5GHz and 2GHz bands */
@@ -81,15 +81,15 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
switch (band) {
case NL80211_BAND_2GHZ:
if (chan == 14)
- return 2484;
+ return MHZ_TO_KHZ(2484);
else if (chan < 14)
- return 2407 + chan * 5;
+ return MHZ_TO_KHZ(2407 + chan * 5);
break;
case NL80211_BAND_5GHZ:
if (chan >= 182 && chan <= 196)
- return 4000 + chan * 5;
+ return MHZ_TO_KHZ(4000 + chan * 5);
else
- return 5000 + chan * 5;
+ return MHZ_TO_KHZ(5000 + chan * 5);
break;
case NL80211_BAND_6GHZ:
/* see 802.11ax D4.1 27.3.22.2 */
@@ -98,17 +98,37 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
break;
case NL80211_BAND_60GHZ:
if (chan < 7)
- return 56160 + chan * 2160;
+ return MHZ_TO_KHZ(56160 + chan * 2160);
break;
default:
;
}
return 0; /* not supported */
}
+
+u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
+{
+ return __ieee80211_channel_to_frequency(chan, band);
+}
+EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
+
+int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
+{
+ return KHZ_TO_MHZ(__ieee80211_channel_to_frequency(chan, band));
+}
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
-int ieee80211_frequency_to_channel(int freq)
+u32 ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
+{
+ return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
+}
+EXPORT_SYMBOL(ieee80211_channel_to_khz);
+
+static int __ieee80211_frequency_to_channel(u32 freq)
{
+ /* TODO: just handle MHz for now */
+ freq = KHZ_TO_MHZ(freq);
+
/* see 802.11 17.3.8.3.2 and Annex J */
if (freq == 2484)
return 14;
@@ -126,9 +146,21 @@ int ieee80211_frequency_to_channel(int freq)
else
return 0;
}
+
+int ieee80211_freq_khz_to_channel(u32 freq)
+{
+ return __ieee80211_frequency_to_channel(freq);
+}
+EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
+
+int ieee80211_frequency_to_channel(int freq)
+{
+ return __ieee80211_frequency_to_channel(MHZ_TO_KHZ(freq));
+}
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
-struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
+static struct ieee80211_channel *
+__ieee80211_get_channel(struct wiphy *wiphy, int freq)
{
enum nl80211_band band;
struct ieee80211_supported_band *sband;
@@ -141,13 +173,27 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
continue;
for (i = 0; i < sband->n_channels; i++) {
- if (sband->channels[i].center_freq == freq)
- return &sband->channels[i];
+ struct ieee80211_channel *chan = &sband->channels[i];
+ if (ieee80211_channel_to_khz(chan) == freq)
+ return chan;
}
}
return NULL;
}
+
+struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
+ u32 freq)
+{
+ return __ieee80211_get_channel(wiphy, freq);
+}
+EXPORT_SYMBOL(ieee80211_get_channel_khz);
+
+struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy,
+ int freq)
+{
+ return __ieee80211_get_channel(wiphy, MHZ_TO_KHZ(freq));
+}
EXPORT_SYMBOL(ieee80211_get_channel);
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
@@ -1670,6 +1716,12 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
+u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
+{
+ return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
+}
+EXPORT_SYMBOL(ieee80211_chandef_to_khz);
+
static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
u32 *beacon_int_gcd,
bool *beacon_int_different)
--
2.20.1
Expect and convert drivers to report the RX frequency to
cfg80211_rx_mgmt() and cfg80211_report_obss_beacon() in
KHz
This doesn't actually change the nl80211 API yet.
Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 5 +++--
drivers/net/wireless/ath/wil6210/wmi.c | 3 ++-
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 6 ++++--
drivers/net/wireless/marvell/mwifiex/util.c | 3 ++-
drivers/staging/wilc1000/cfg80211.c | 2 +-
include/net/cfg80211.h | 4 ++--
net/mac80211/rx.c | 6 ++++--
net/wireless/nl80211.c | 4 ++--
8 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 6885d2ded53a..4b70ffe04e58 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -619,7 +619,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
+ cfg80211_rx_mgmt(&vif->wdev, MHZ_TO_KHZ(freq), 0, ev->data,
+ dlen, 0);
return 0;
}
@@ -658,7 +659,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
+ cfg80211_rx_mgmt(&vif->wdev, MHZ_TO_KHZ(freq), 0, ev->data, dlen, 0);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 23e1ed6a9d6d..860c9e2656e5 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -905,7 +905,8 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
}
} else {
mutex_lock(&wil->vif_mutex);
- cfg80211_rx_mgmt(vif_to_radio_wdev(wil, vif), freq, signal,
+ cfg80211_rx_mgmt(vif_to_radio_wdev(wil, vif),
+ MHZ_TO_KHZ(freq), signal,
(void *)rx_mgmt_frame, d_len, 0);
mutex_unlock(&wil->vif_mutex);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 1f5deea5a288..f4881b389148 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -1423,7 +1423,8 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
NL80211_BAND_5GHZ);
wdev = &ifp->vif->wdev;
- cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
+ cfg80211_rx_mgmt(wdev, MHZ_TO_KHZ(freq), 0, (u8 *)mgmt_frame,
+ mgmt_frame_len, 0);
kfree(mgmt_frame);
return 0;
@@ -1908,7 +1909,8 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
NL80211_BAND_2GHZ :
NL80211_BAND_5GHZ);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
+ cfg80211_rx_mgmt(&vif->wdev, MHZ_TO_KHZ(freq), 0, mgmt_frame,
+ mgmt_frame_len, 0);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
mgmt_frame_len, e->datalen, ch.chspec, freq);
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index de89a1e710b1..8d449d723dd2 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -425,7 +425,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
pkt_len -= ETH_ALEN + sizeof(pkt_len);
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
- cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
+ cfg80211_rx_mgmt(&priv->wdev,
+ MHZ_TO_KHZ(priv->roc_cfg.chan.center_freq),
CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
0);
diff --git a/drivers/staging/wilc1000/cfg80211.c b/drivers/staging/wilc1000/cfg80211.c
index 4863e516ff13..93c3716435de 100644
--- a/drivers/staging/wilc1000/cfg80211.c
+++ b/drivers/staging/wilc1000/cfg80211.c
@@ -1077,7 +1077,7 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
}
}
- cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
+ cfg80211_rx_mgmt(&priv->wdev, MHZ_TO_KHZ(freq), 0, buff, size, 0);
}
static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 000721915f21..3cf7a84af53e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6937,7 +6937,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
/**
* cfg80211_rx_mgmt - notification of received, unprocessed management frame
* @wdev: wireless device receiving the frame
- * @freq: Frequency on which the frame was received in MHz
+ * @freq: Frequency on which the frame was received in KHz
* @sig_dbm: signal strength in dBm, or 0 if unknown
* @buf: Management frame (header + body)
* @len: length of the frame data
@@ -7155,7 +7155,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
* @wiphy: The wiphy that received the beacon
* @frame: the frame
* @len: length of the frame
- * @freq: frequency the frame was received on
+ * @freq: frequency the frame was received on in KHz
* @sig_dbm: signal strength in dBm, or 0 if unknown
*
* Use this function to report to userspace when a beacon was
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 0b6dca4c0c7d..a9f632992853 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3085,7 +3085,8 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
rx->skb->data, rx->skb->len,
- status->freq, sig);
+ ieee80211_rx_status_to_khz(status),
+ sig);
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
}
@@ -3431,7 +3432,8 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
!(status->flag & RX_FLAG_NO_SIGNAL_VAL))
sig = status->signal;
- if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
+ if (cfg80211_rx_mgmt(&rx->sdata->wdev,
+ ieee80211_rx_status_to_khz(status), sig,
rx->skb->data, rx->skb->len, 0)) {
if (rx->sta)
rx->sta->rx_stats.packets++;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5fa402144cda..ff66f7d3e04f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16226,7 +16226,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
netdev->ifindex)) ||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
NL80211_ATTR_PAD) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
@@ -16877,7 +16877,7 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq))) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
--
2.20.1
NL80211_ATTR_SCAN_FREQUENCIES_KHZ are optional in addition
to the MHz frequencies specified in
NL80211_ATTR_SCAN_FREQUENCIES.
Signed-off-by: Thomas Pedersen <[email protected]>
---
include/uapi/linux/nl80211.h | 2 ++
net/wireless/nl80211.c | 23 +++++++++++++++++------
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 28401f039d75..de80ae4f8aae 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2430,6 +2430,7 @@ enum nl80211_commands {
* @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
* the allowed channel bandwidth configurations. (u8 attribute)
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ * @NL80211_ATTR_SCAN_FREQUENCIES_KHZ: nested attribute with frequencies (in KHz)
*
* @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
* (u16).
@@ -2957,6 +2958,7 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_FREQ_OFFSET,
NL80211_ATTR_CENTER_FREQ1_OFFSET,
+ NL80211_ATTR_SCAN_FREQUENCIES_KHZ,
/* add attributes here, update the policy in nl80211.c */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ea9310f6d981..5a8a30282bf2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -665,6 +665,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
[NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
[NL80211_ATTR_WIPHY_FREQ_OFFSET] = { .type = NLA_U32 },
+ [NL80211_ATTR_SCAN_FREQUENCIES_KHZ] = { .type = NLA_NESTED },
};
/* policy for the key attributes */
@@ -7749,6 +7750,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
struct cfg80211_scan_request *request;
+ struct nlattr *scan_freqs = NULL;
+ bool scan_freqs_khz = false;
struct nlattr *attr;
struct wiphy *wiphy;
int err, tmp, n_ssids = 0, n_channels, i;
@@ -7767,9 +7770,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
goto unlock;
}
- if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
- n_channels = validate_scan_freqs(
- info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES_KHZ]) {
+ scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQUENCIES_KHZ];
+ scan_freqs_khz = true;
+ } else if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES])
+ scan_freqs = info->attrs[NL80211_ATTR_SCAN_FREQUENCIES];
+
+ if (scan_freqs) {
+ n_channels = validate_scan_freqs(scan_freqs);
if (!n_channels) {
err = -EINVAL;
goto unlock;
@@ -7817,13 +7825,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
i = 0;
- if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ if (scan_freqs) {
/* user specified, bail out if channel not found */
- nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
+ nla_for_each_nested(attr, scan_freqs, tmp) {
struct ieee80211_channel *chan;
+ int freq = nla_get_u32(attr);
- chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+ if (!scan_freqs_khz)
+ freq = MHZ_TO_KHZ(freq);
+ chan = ieee80211_get_channel_khz(wiphy, freq);
if (!chan) {
err = -EINVAL;
goto out_free;
--
2.20.1
RX status needs a KHz component, so add freq_offset. We
can make ampdu_reference u16 since it is probably
sufficient to be able to distinguish 64k different
A-MPDUs.
Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/mac80211.h | 10 +++++++++-
net/mac80211/mlme.c | 6 ++++--
net/mac80211/rx.c | 1 +
net/mac80211/scan.c | 3 ++-
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b6b4de0e4b5e..459ec57248fc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1333,6 +1333,7 @@ enum mac80211_rx_encoding {
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
* This field must be set for management frames, but isn't strictly needed
* for data (other) frames - for those it only affects radiotap reporting.
+ * @freq_offset: positive KHz component of @freq.
* @signal: signal strength when receiving this frame, either in dBm, in dB or
* unspecified depending on the hardware capabilities flags
* @IEEE80211_HW_SIGNAL_*
@@ -1361,9 +1362,10 @@ struct ieee80211_rx_status {
u64 mactime;
u64 boottime_ns;
u32 device_timestamp;
- u32 ampdu_reference;
u32 flag;
+ u16 ampdu_reference;
u16 freq;
+ u16 freq_offset;
u8 enc_flags;
u8 encoding:2, bw:3, he_ru:3;
u8 he_gi:2, he_dcm:1;
@@ -1379,6 +1381,12 @@ struct ieee80211_rx_status {
u8 zero_length_psdu_type;
};
+static inline u32
+ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
+{
+ return MHZ_TO_KHZ(rx_status->freq) + rx_status->freq_offset;
+}
+
/**
* struct ieee80211_vendor_radiotap - vendor radiotap data information
* @present: presence bitmap for this vendor namespace
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4eebee49bb7d..e5bcd786e333 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3669,7 +3669,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sdata_assert_lock(sdata);
- channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+ channel = ieee80211_get_channel_khz(local->hw.wiphy,
+ ieee80211_rx_status_to_khz(rx_status));
if (!channel)
return;
@@ -3885,7 +3886,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
return;
}
- if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
+ if (rx_status->freq != chanctx_conf->def.chan->center_freq ||
+ rx_status->freq_offset != chanctx_conf->def.chan->freq_offset) {
rcu_read_unlock();
return;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 91a13aee4378..0b6dca4c0c7d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -412,6 +412,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos++;
/* IEEE80211_RADIOTAP_CHANNEL */
+ /* TODO: frequency offset in KHz */
put_unaligned_le16(status->freq, pos);
pos += 2;
if (status->bw == RATE_INFO_BW_10)
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4d14118dddca..5db15996524f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -275,7 +275,8 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
return;
}
- channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+ channel = ieee80211_get_channel_khz(local->hw.wiphy,
+ ieee80211_rx_status_to_khz(rx_status));
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;
--
2.20.1
cfg80211 recently gained the ability to understand a
frequency offset component in KHz. Expose this in nl80211
through the new attributes NL80211_ATTR_WIPHY_FREQ_OFFSET,
NL80211_FREQUENCY_ATTR_OFFSET,
NL80211_ATTR_CENTER_FREQ1_OFFSET, and
NL80211_BSS_FREQUENCY_OFFSET.
These add support to send and receive a KHz offset
component with the following NL80211 commands:
- NL80211_CMD_FRAME
- NL80211_CMD_GET_SCAN
- NL80211_CMD_AUTHENTICATE
- NL80211_CMD_ASSOCIATE
- NL80211_CMD_CONNECT
Along with any other command which takes a chandef, ie:
TODO: several of these commands will eventually just
ignore the _OFFSET component, like _JOIN_MESH,
_CMD_RADAR_DETECT, etc. Should return an error to give
user a hint things won't work as expected?
- NL80211_CMD_SET_CHANNEL
- NL80211_CMD_SET_WIPHY
- NL80211_CMD_START_AP
- NL80211_CMD_RADAR_DETECT
- NL80211_CMD_NOTIFY_RADAR
- NL80211_CMD_CHANNEL_SWITCH
- NL80211_JOIN_IBSS
- NL80211_CMD_REMAIN_ON_CHANNEL
- NL80211_CMD_JOIN_CB
- NL80211_CMD_JOIN_MESH
- NL80211_CMD_TDLS_CHANNEL_SWITCH
Signed-off-by: Thomas Pedersen <[email protected]>
---
include/uapi/linux/nl80211.h | 49 ++++++++++++++++--------
net/wireless/nl80211.c | 72 +++++++++++++++++++++++++++---------
2 files changed, 87 insertions(+), 34 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 2b691161830f..28401f039d75 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -296,13 +296,14 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
- * attributes determining the channel width; this is used for setting
- * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
- * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
- * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
- * instead, the support here is for backward compatibility only.
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the
+ * channel width; this is used for setting monitor mode channel),
+ * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG,
+ * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or
+ * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel,
+ * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward
+ * compatibility only.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -351,7 +352,8 @@
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the
+ * attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -536,11 +538,12 @@
* interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
* BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
* the SSID (mainly for association, but is included in authentication
- * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
- * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
- * is used to specify the authentication type. %NL80211_ATTR_IE is used to
- * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
- * to be added to the frame.
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ +
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the
+ * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the
+ * authentication type. %NL80211_ATTR_IE is used to define IEs
+ * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added
+ * to the frame.
* When used as an event, this reports reception of an Authentication
* frame in station and IBSS modes when the local MLME processed the
* frame, i.e., it was for the local STA and was received in correct
@@ -595,8 +598,9 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
- * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE,
+ * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
* %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
@@ -1422,7 +1426,8 @@ enum nl80211_commands {
* of &enum nl80211_chan_width, describing the channel width. See the
* documentation of the enum for more information.
* @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
- * channel, used for anything but 20 MHz bandwidth
+ * channel, used for anything but 20 MHz bandwidth. In S1G this is the
+ * operating channel center frequency.
* @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
* channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
@@ -2469,6 +2474,11 @@ enum nl80211_commands {
* entry without having to force a disconnection after the PMK timeout. If
* no roaming occurs between the reauth threshold and PMK expiration,
* disassociation is still forced.
+ * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated
+ * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with
+ * an %NL80211_ATTR_WIPHY_FREQ_OFFSET.
+ * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the
+ * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2945,6 +2955,9 @@ enum nl80211_attrs {
NL80211_ATTR_PMK_LIFETIME,
NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+ NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ NL80211_ATTR_CENTER_FREQ1_OFFSET,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3666,6 +3679,7 @@ enum nl80211_wmm_rule {
* (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
* in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3696,6 +3710,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
NL80211_FREQUENCY_ATTR_NO_HE,
+ NL80211_FREQUENCY_ATTR_OFFSET,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4466,6 +4481,7 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
* Contains a nested array of signal strength attributes (u8, dBm),
* using the nesting index as the antenna number.
+ * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -4490,6 +4506,7 @@ enum nl80211_bss {
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
NL80211_BSS_CHAIN_SIGNAL,
+ NL80211_BSS_FREQUENCY_OFFSET,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ff66f7d3e04f..ea9310f6d981 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -365,6 +365,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
[NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
+ [NL80211_ATTR_CENTER_FREQ1_OFFSET] = { .type = NLA_U32 },
[NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
@@ -663,6 +664,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
[NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
[NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
+ [NL80211_ATTR_WIPHY_FREQ_OFFSET] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -947,6 +949,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
chan->center_freq))
goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_OFFSET, chan->freq_offset))
+ goto nla_put_failure;
+
if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
goto nla_put_failure;
@@ -1352,13 +1357,11 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
}
static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
- struct nlattr *tb)
+ u32 freq)
{
struct ieee80211_channel *chan;
- if (tb == NULL)
- return NULL;
- chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
+ chan = ieee80211_get_channel_khz(wiphy, freq);
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
return NULL;
return chan;
@@ -2813,13 +2816,17 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
if (!attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
- control_freq = nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]);
+ control_freq = MHZ_TO_KHZ(
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
+ control_freq +=
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
memset(chandef, 0, sizeof(*chandef));
-
- chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
+ chandef->chan = ieee80211_get_channel_khz(&rdev->wiphy, control_freq);
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
- chandef->center_freq1 = control_freq;
+ chandef->center_freq1 = KHZ_TO_MHZ(control_freq);
+ chandef->freq1_offset = control_freq % 1000;
chandef->center_freq2 = 0;
/* Primary channel not allowed */
@@ -2870,6 +2877,9 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
if (attrs[NL80211_ATTR_CENTER_FREQ1])
chandef->center_freq1 =
nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]);
+ if (attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET])
+ chandef->freq1_offset = nla_get_u32(
+ attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET]);
if (attrs[NL80211_ATTR_CENTER_FREQ2])
chandef->center_freq2 =
nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
@@ -3302,6 +3312,9 @@ static int nl80211_send_chandef(struct sk_buff *msg,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq))
return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ chandef->chan->freq_offset))
+ return -ENOBUFS;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
@@ -8906,6 +8919,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
goto nla_put_failure;
if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
+ nla_put_u32(msg, NL80211_BSS_FREQUENCY_OFFSET,
+ res->channel->freq_offset) ||
nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
jiffies_to_msecs(jiffies - intbss->ts)))
@@ -9174,6 +9189,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
+ u32 freq;
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
@@ -9230,8 +9246,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- chan = nl80211_get_valid_chan(&rdev->wiphy,
- info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
+ freq +=
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
+
+ chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
if (!chan)
return -EINVAL;
@@ -9421,6 +9441,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_assoc_request req = {};
const u8 *bssid, *ssid;
int err, ssid_len = 0;
+ u32 freq;
if (dev->ieee80211_ptr->conn_owner_nlportid &&
dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
@@ -9440,8 +9461,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- chan = nl80211_get_valid_chan(&rdev->wiphy,
- info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ freq = MHZ_TO_KHZ(nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
+ freq +=
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
+ chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
if (!chan)
return -EINVAL;
@@ -10121,6 +10145,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_connect_params connect;
struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL;
+ u32 freq = 0;
int err;
memset(&connect, 0, sizeof(connect));
@@ -10191,14 +10216,21 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.prev_bssid =
nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
- if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- connect.channel = nl80211_get_valid_chan(
- wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ])
+ freq = MHZ_TO_KHZ(nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])
+ freq +=
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
+
+ if (freq) {
+ connect.channel = nl80211_get_valid_chan(wiphy, freq);
if (!connect.channel)
return -EINVAL;
} else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
- connect.channel_hint = nl80211_get_valid_chan(
- wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
+ freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
+ freq = MHZ_TO_KHZ(freq);
+ connect.channel_hint = nl80211_get_valid_chan(wiphy, freq);
if (!connect.channel_hint)
return -EINVAL;
}
@@ -16227,6 +16259,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
NL80211_ATTR_PAD) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
@@ -16877,7 +16910,10 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq))) ||
+ (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ KHZ_TO_MHZ(freq)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ freq % 1000))) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
--
2.20.1
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>
> +/**
> + * ieee80211_get_channel_khz - get channel struct from wiphy for specified
> + * frequency
You can't line-break there, but I think I learned a while back that you
can do
/**
* ieee80211_get_channel_khz -
* get channel ...
or something like that. Maybe try?
> +/**
> + * ieee80211_chandef_to_khz - convert chandef to frequency in KHz
> + *
> + * @chandef: the chandef to convert
> + *
> + * Returns the center frequency of chandef (1st segment) in KHz.
> + */
> +u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef);
Isn't this one trivial, and probably better inlined (mhz*1000 + khz)?
> +u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
> +{
> + return __ieee80211_channel_to_frequency(chan, band);
> +}
> +EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
> +
> +int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
> +{
> + return KHZ_TO_MHZ(__ieee80211_channel_to_frequency(chan, band));
> +}
> EXPORT_SYMBOL(ieee80211_channel_to_frequency);
>
> -int ieee80211_frequency_to_channel(int freq)
> +u32 ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
> +{
> + return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
> +}
> +EXPORT_SYMBOL(ieee80211_channel_to_khz);
Some of these should probably be inlines? Or maybe all of them, and
> +static int __ieee80211_frequency_to_channel(u32 freq)
export the double-underscore helpers like this one instead? That'd still
be less code overall, IMHO.
> +int ieee80211_freq_khz_to_channel(u32 freq)
> +{
> + return __ieee80211_frequency_to_channel(freq);
> +}
> +EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
> +
> +int ieee80211_frequency_to_channel(int freq)
> +{
> + return __ieee80211_frequency_to_channel(MHZ_TO_KHZ(freq));
> +}
> EXPORT_SYMBOL(ieee80211_frequency_to_channel);
similarly here, I guess.
> +struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
> + u32 freq)
> +{
> + return __ieee80211_get_channel(wiphy, freq);
> +}
> +EXPORT_SYMBOL(ieee80211_get_channel_khz);
> +
> +struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy,
> + int freq)
> +{
> + return __ieee80211_get_channel(wiphy, MHZ_TO_KHZ(freq));
> +}
> EXPORT_SYMBOL(ieee80211_get_channel);
And maybe here? In fact, how is __ieee80211_get_channel() even different
from ieee80211_get_channel_khz()?
> @@ -1670,6 +1716,12 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
> }
> EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
>
> +u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
> +{
> + return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
> +}
> +EXPORT_SYMBOL(ieee80211_chandef_to_khz);
That's like I thought above.
I think that'd have less code overall, don't you think?
johannes
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
> ie. ignore
> for mesh, ibss, HT/VHT specific stuff, TDLS, etc.
This makes sense, but I don't see that you prevent using mesh, ibss and
perhaps TDLS on s1g channels?
Or do we not expect drivers/devices that support this, as well as S1G
channels?
johannes
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
> RX status needs a KHz component, so add freq_offset. We
> can make ampdu_reference u16 since it is probably
> sufficient to be able to distinguish 64k different
> A-MPDUs.
Is that necessary? Reads like we have 2 bytes free there?
And we only need 13 bits for the frequency (up to 8192 MHz, 60 GHz isn't
supported), so we could take out a few fractional ones for the S1G part?
Dunno, I mean, we probably also don't need the A-MPDU reference, even
radiotap doesn't make much representation on this, but it sort of
implies that it should be unique in a capture file, for which 16 bits
wouldn't be enough? (should probably clarify that though and say that
you should look only "close by" or something?)
johannes
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>
> TODO: several of these commands will eventually just
> ignore the _OFFSET component, like _JOIN_MESH,
> _CMD_RADAR_DETECT, etc. Should return an error to give
> user a hint things won't work as expected?
Wouldn't most of them already require that a channel with the given
frequency exists, and thus fail anyway?
johannes
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>
> + [NL80211_ATTR_CENTER_FREQ1_OFFSET] = { .type = NLA_U32 },
These should probably all be something like
NLA_POLICY_RANGE(NLA_U32, 0, 999)?
johannes
On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
> Some cfg80211 and nl80211 internals have been converted to handle units
> of KHz, which is not unprecedented (net/wireless/reg.c), and the
> collateral damage is localized.
:)
> One thing which is still unclear is backward compatibility in nl80211.
> If a frequency offset is supplied to an older kernel, it'll just
> silently fail to do the right thing.
But will it? It mostly requires to have a struct ieee80211_channel
registered with the wiphy for a given frequency, and won't find that?
But speaking of which - I was expecting to see a new *band* here for
S1G, so that you can actually register the channels properly in the
wiphy struct? Or is that just not part of this patchset yet?
johannes
On 3/31/20 11:54 PM, Johannes Berg wrote:
> On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>>
>> +/**
>> + * ieee80211_get_channel_khz - get channel struct from wiphy for specified
>> + * frequency
>
> You can't line-break there, but I think I learned a while back that you
> can do
>
> /**
> * ieee80211_get_channel_khz -
> * get channel ...
>
> or something like that. Maybe try?
Looks like it renders ok though:
---
.. c:function:: struct ieee80211_channel * ieee80211_get_channel (struct wiphy * wiphy, int freq)
get channel struct from wiphy for specified frequency
**Parameters**
``struct wiphy * wiphy``
the struct wiphy to get the channel for
``int freq``
the center frequency (in MHz) of the channel
---
Documentation/doc-guide/kernel-doc.rst says:
The brief description following the function name may span multiple lines, and
ends with an argument description, a blank comment line, or the end of the
comment block.
>> +/**
>> + * ieee80211_chandef_to_khz - convert chandef to frequency in KHz
>> + *
>> + * @chandef: the chandef to convert
>> + *
>> + * Returns the center frequency of chandef (1st segment) in KHz.
>> + */
>> +u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef);
>
> Isn't this one trivial, and probably better inlined (mhz*1000 + khz)?
Do you mean open code the conversion? I would prefer not to. If you
meant make it an inline function then yes probably.
>> +u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
>> +{
>> + return __ieee80211_channel_to_frequency(chan, band);
>> +}
>> +EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
>> +
>> +int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
>> +{
>> + return KHZ_TO_MHZ(__ieee80211_channel_to_frequency(chan, band));
>> +}
>> EXPORT_SYMBOL(ieee80211_channel_to_frequency);
>>
>> -int ieee80211_frequency_to_channel(int freq)
>> +u32 ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
>> +{
>> + return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
>> +}
>> +EXPORT_SYMBOL(ieee80211_channel_to_khz);
>
> Some of these should probably be inlines? Or maybe all of them, and
>
>> +static int __ieee80211_frequency_to_channel(u32 freq)
>
> export the double-underscore helpers like this one instead? That'd still
> be less code overall, IMHO.
I didn't want to change the interface for
ieee80211_frequency_to_channel(). It's a little confusing that one takes
MHz, but the __ieee80211_frequency_to_channel() takes KHz? By giving the
_khz() hint in the wrapper we were trying to make it explicit. Similar
to below.
>> +int ieee80211_freq_khz_to_channel(u32 freq)
>> +{
>> + return __ieee80211_frequency_to_channel(freq);
>> +}
>> +EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
>> +
>> +int ieee80211_frequency_to_channel(int freq)
>> +{
>> + return __ieee80211_frequency_to_channel(MHZ_TO_KHZ(freq));
>> +}
>> EXPORT_SYMBOL(ieee80211_frequency_to_channel);
>
> similarly here, I guess.
>
>> +struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
>> + u32 freq)
>> +{
>> + return __ieee80211_get_channel(wiphy, freq);
>> +}
>> +EXPORT_SYMBOL(ieee80211_get_channel_khz);
>> +
>> +struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy,
>> + int freq)
>> +{
>> + return __ieee80211_get_channel(wiphy, MHZ_TO_KHZ(freq));
>> +}
>> EXPORT_SYMBOL(ieee80211_get_channel);
>
> And maybe here? In fact, how is __ieee80211_get_channel() even different
> from ieee80211_get_channel_khz()?
It's not. I thought the _khz() hint was helpful for the reader to keep
the units straight.
>> @@ -1670,6 +1716,12 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
>> }
>> EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
>>
>> +u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
>> +{
>> + return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
>> +}
>> +EXPORT_SYMBOL(ieee80211_chandef_to_khz);
>
> That's like I thought above.
>
> I think that'd have less code overall, don't you think?
What do you think about keeping the interfaces in place, but otherwise
converting them to inline functions (where it makes sense)?
I'd like to avoid open coding the conversions and otherwise keep the
gory internals of the channel structures hidden from the caller.
--
thomas
On 3/31/20 11:59 PM, Johannes Berg wrote:
> On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>> ie. ignore
>> for mesh, ibss, HT/VHT specific stuff, TDLS, etc.
>
> This makes sense, but I don't see that you prevent using mesh, ibss and
> perhaps TDLS on s1g channels?
>
> Or do we not expect drivers/devices that support this, as well as S1G
> channels?
Well it's really orthogonal to S1G (maybe a new 2412.5Mhz channel opens
up :)). We should probably return an error 'if (chan->freq_offset)' or
so for features which have not yet been tested / implemented for
frequency offset.
--
thomas
On Wed, 2020-04-01 at 10:39 -0700, Thomas Pedersen wrote:
> On 3/31/20 11:59 PM, Johannes Berg wrote:
> > On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
> > > ie. ignore
> > > for mesh, ibss, HT/VHT specific stuff, TDLS, etc.
> >
> > This makes sense, but I don't see that you prevent using mesh, ibss and
> > perhaps TDLS on s1g channels?
> >
> > Or do we not expect drivers/devices that support this, as well as S1G
> > channels?
>
> Well it's really orthogonal to S1G (maybe a new 2412.5Mhz channel opens
> up :)). We should probably return an error 'if (chan->freq_offset)' or
> so for features which have not yet been tested / implemented for
> frequency offset.
OK, fair enough.
johannes
On Wed, 2020-04-01 at 10:30 -0700, Thomas Pedersen wrote:
>
> ---
> .. c:function:: struct ieee80211_channel * ieee80211_get_channel (struct wiphy * wiphy, int freq)
>
> get channel struct from wiphy for specified frequency
>
> **Parameters**
>
> ``struct wiphy * wiphy``
> the struct wiphy to get the channel for
>
> ``int freq``
> the center frequency (in MHz) of the channel
> ---
>
> Documentation/doc-guide/kernel-doc.rst says:
>
> The brief description following the function name may span multiple lines, and
> ends with an argument description, a blank comment line, or the end of the
> comment block.
Interesting. I guess they must've fixed this at some point - at least I
_seem_ to remember getting wrong output with it. Thanks for the
correction!
> > > +/**
> > > + * ieee80211_chandef_to_khz - convert chandef to frequency in KHz
> > > + *
> > > + * @chandef: the chandef to convert
> > > + *
> > > + * Returns the center frequency of chandef (1st segment) in KHz.
> > > + */
> > > +u32 ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef);
> >
> > Isn't this one trivial, and probably better inlined (mhz*1000 + khz)?
>
> Do you mean open code the conversion? I would prefer not to. If you
> meant make it an inline function then yes probably.
Right, I meant making it an inline.
> > > +static int __ieee80211_frequency_to_channel(u32 freq)
> >
> > export the double-underscore helpers like this one instead? That'd still
> > be less code overall, IMHO.
>
> I didn't want to change the interface for
> ieee80211_frequency_to_channel(). It's a little confusing that one takes
> MHz, but the __ieee80211_frequency_to_channel() takes KHz? By giving the
> _khz() hint in the wrapper we were trying to make it explicit. Similar
> to below.
Right. I think that's fine. I was just wondering if / thinking that it
may be better to just export ieee80211_freq_khz_to_channel(), and
express the other ones as inline function in terms of that?
> > And maybe here? In fact, how is __ieee80211_get_channel() even different
> > from ieee80211_get_channel_khz()?
>
> It's not. I thought the _khz() hint was helpful for the reader to keep
> the units straight.
Agree, but then you don't need the double-underscore version and can
just express the old one in terms of the _khz one?
> What do you think about keeping the interfaces in place, but otherwise
> converting them to inline functions (where it makes sense)?
Yes, I think that's what I had in mind.
> I'd like to avoid open coding the conversions and otherwise keep the
> gory internals of the channel structures hidden from the caller.
Agree.
johannes
On 4/1/20 12:08 AM, Johannes Berg wrote:
> On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>> RX status needs a KHz component, so add freq_offset. We
>> can make ampdu_reference u16 since it is probably
>> sufficient to be able to distinguish 64k different
>> A-MPDUs.
>
> Is that necessary? Reads like we have 2 bytes free there?
Indeed there is, maybe this wasn't the case on 4.9 where I originally
wrote this patch.
> And we only need 13 bits for the frequency (up to 8192 MHz, 60 GHz isn't
> supported), so we could take out a few fractional ones for the S1G part?
Makes sense, and yeah we really don't need 2 whole bytes to essentially
express "+0.5 MHz". Will shorten the frequency and just use a single bit
indicating offset or not.
> Dunno, I mean, we probably also don't need the A-MPDU reference, even
> radiotap doesn't make much representation on this, but it sort of
> implies that it should be unique in a capture file, for which 16 bits
> wouldn't be enough? (should probably clarify that though and say that
> you should look only "close by" or something?)
Yeah. I'll drop this for now, but maybe the space will come in handy in
the future.
--
thomas
On 4/1/20 12:10 AM, Johannes Berg wrote:
> On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>>
>> TODO: several of these commands will eventually just
>> ignore the _OFFSET component, like _JOIN_MESH,
>> _CMD_RADAR_DETECT, etc. Should return an error to give
>> user a hint things won't work as expected?
>
> Wouldn't most of them already require that a channel with the given
> frequency exists, and thus fail anyway?
Well I was thinking of the case where you have:
ch 2: 903MHz
ch 3: 903.5Mhz
userspace tries to eg. join a mesh on channel 3 by sending 903MHz +
500KHz, the (old) kernel interprets this as channel 2 and happily joins
on the wrong channel. However this only applies on a new band which
doesn't even exist yet, and if we return an error for commands which
have not yet been tested with frequency offset nothing unexpected will
happen.
--
thomas
On 4/1/20 12:15 AM, Johannes Berg wrote:
> On Tue, 2020-03-31 at 23:21 -0700, Thomas Pedersen wrote:
>
>> Some cfg80211 and nl80211 internals have been converted to handle units
>> of KHz, which is not unprecedented (net/wireless/reg.c), and the
>> collateral damage is localized.
>
> :)
>
>> One thing which is still unclear is backward compatibility in nl80211.
>> If a frequency offset is supplied to an older kernel, it'll just
>> silently fail to do the right thing.
>
> But will it? It mostly requires to have a struct ieee80211_channel
> registered with the wiphy for a given frequency, and won't find that?
I was worried the wrong ("rounded down") channel would be found, but I
think the point is mostly moot since that channel wouldn't exist either.
> But speaking of which - I was expecting to see a new *band* here for
> S1G, so that you can actually register the channels properly in the
> wiphy struct? Or is that just not part of this patchset yet?
Yeah just trying to focus on the frequency offset stuff and keep S1G out
of it for now. Do you think it would be helpful to cap it with the new
S1G band definition?
--
thomas
On 4/1/20 10:53 AM, Johannes Berg wrote:
> On Wed, 2020-04-01 at 10:30 -0700, Thomas Pedersen wrote:
>>>> +static int __ieee80211_frequency_to_channel(u32 freq)
>>>
>>> export the double-underscore helpers like this one instead? That'd still
>>> be less code overall, IMHO.
>>
>> I didn't want to change the interface for
>> ieee80211_frequency_to_channel(). It's a little confusing that one takes
>> MHz, but the __ieee80211_frequency_to_channel() takes KHz? By giving the
>> _khz() hint in the wrapper we were trying to make it explicit. Similar
>> to below.
>
> Right. I think that's fine. I was just wondering if / thinking that it
> may be better to just export ieee80211_freq_khz_to_channel(), and
> express the other ones as inline function in terms of that?
>
>>> And maybe here? In fact, how is __ieee80211_get_channel() even different
>>> from ieee80211_get_channel_khz()?
>>
>> It's not. I thought the _khz() hint was helpful for the reader to keep
>> the units straight.
>
> Agree, but then you don't need the double-underscore version and can
> just express the old one in terms of the _khz one?
>
>> What do you think about keeping the interfaces in place, but otherwise
>> converting them to inline functions (where it makes sense)?
>
> Yes, I think that's what I had in mind.
OK I get it. That is a lot cleaner.
--
thomas