mac80211: handle channel frequency offset
authorThomas Pedersen <thomas@adapt-ip.com>
Thu, 2 Apr 2020 01:18:04 +0000 (18:18 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 24 Apr 2020 10:33:43 +0000 (12:33 +0200)
cfg80211_chan_def and ieee80211_channel recently gained a
frequency offset component. Handle this where it makes
sense (potentially required by S1G channels).

For IBSS, TDLS, CSA, and ROC we return -EOPNOTSUPP if a
channel with frequency offset is passed, since they may or
may not work. Once someone tests and verifies these
commands work on thos types of channels, we can remove
that error.

join_ocb and join_mesh look harmless because they use a
simple ieee80211_vif_use_channel(), which is using an
already verified channel, so we let those through.

Signed-off-by: Thomas Pedersen <thomas@adapt-ip.com>
Link: https://lore.kernel.org/r/20200402011810.22947-4-thomas@adapt-ip.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ibss.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/scan.c
net/mac80211/tdls.c
net/mac80211/trace.h

index f0d43b9cfa43afbaa61d3e240575432956ecdeb5..ae3e06375a28fe10fed2800a7da2514eadb96c03 100644 (file)
@@ -3287,6 +3287,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       if (params->chandef.chan->freq_offset) {
+               /* this may work, but is untested */
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
        ch_switch.timestamp = 0;
index 9c94baaf693cbb531e57fafdf26144667a4fe68a..e6e192f53e4e0eab94877e0ab5ad786478d3ebbc 100644 (file)
@@ -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
index d40744903fa90f596435d7e9fdb4d46ec39683b3..2479cd48fed096e6ac283989c5d00f101a20050d 100644 (file)
@@ -1758,6 +1758,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        int i;
        int ret;
 
+       if (params->chandef.chan->freq_offset) {
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+       }
+
        ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
                                            &params->chandef,
                                            sdata->wdev.iftype);
index a0cb052ea30d51a549fdabe3fbb33ceb6d9a8f50..dfcee5e462da073c0160a78f3ef94a9c76c06f8f 100644 (file)
@@ -107,13 +107,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;
index 59a35c7997c3ac63b33991ef751bb08fcb6ab25f..acc8adf50d69474f246aa27dd93184765a50669f 100644 (file)
@@ -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);
index c710504ccf1aa3990ac41aa6895d8dbf32a5fa56..db3b8bf756562a79c43fdb34b1f284fc47d7127c 100644 (file)
@@ -557,6 +557,10 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
        lockdep_assert_held(&local->mtx);
 
+       if (channel->freq_offset)
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+
        if (local->use_chanctx && !local->ops->remain_on_channel)
                return -EOPNOTSUPP;
 
index fdac8192a5198886986e0a7e0f6d33e8e5f17156..4d14118dddca2a7edd7dcc51b5e6163657878172 100644 (file)
@@ -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:
index 7ff22f9d6e8045a5bc1a6e843b273757084c2389..8ad420db37667e84476d36dbdbd9f1febe16df0d 100644 (file)
@@ -1566,6 +1566,10 @@ ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        u32 ch_sw_tm_ie;
        int ret;
 
+       if (chandef->chan->freq_offset)
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+
        mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, addr);
        if (!sta) {
index 427f51a0a9945a8d885af104f350e821f666336e..1b4709694d2a89213a774284a5927c982c6b22f6 100644 (file)
 #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);
                        }