LCOV - code coverage report
Current view: top level - net/wireless - chan.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 371 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 29 0.0 %
Branches: 0 459 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * This file contains helper code to handle channel
       4                 :            :  * settings and keeping track of what is possible at
       5                 :            :  * any point in time.
       6                 :            :  *
       7                 :            :  * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
       8                 :            :  * Copyright 2013-2014  Intel Mobile Communications GmbH
       9                 :            :  * Copyright 2018       Intel Corporation
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/export.h>
      13                 :            : #include <net/cfg80211.h>
      14                 :            : #include "core.h"
      15                 :            : #include "rdev-ops.h"
      16                 :            : 
      17                 :            : static bool cfg80211_valid_60g_freq(u32 freq)
      18                 :            : {
      19                 :          0 :         return freq >= 58320 && freq <= 70200;
      20                 :            : }
      21                 :            : 
      22                 :          0 : void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
      23                 :            :                              struct ieee80211_channel *chan,
      24                 :            :                              enum nl80211_channel_type chan_type)
      25                 :            : {
      26   [ #  #  #  # ]:          0 :         if (WARN_ON(!chan))
      27                 :          0 :                 return;
      28                 :            : 
      29                 :          0 :         chandef->chan = chan;
      30                 :          0 :         chandef->center_freq2 = 0;
      31                 :          0 :         chandef->edmg.bw_config = 0;
      32                 :          0 :         chandef->edmg.channels = 0;
      33                 :            : 
      34   [ #  #  #  #  :          0 :         switch (chan_type) {
                      # ]
      35                 :            :         case NL80211_CHAN_NO_HT:
      36                 :          0 :                 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
      37                 :          0 :                 chandef->center_freq1 = chan->center_freq;
      38                 :          0 :                 break;
      39                 :            :         case NL80211_CHAN_HT20:
      40                 :          0 :                 chandef->width = NL80211_CHAN_WIDTH_20;
      41                 :          0 :                 chandef->center_freq1 = chan->center_freq;
      42                 :          0 :                 break;
      43                 :            :         case NL80211_CHAN_HT40PLUS:
      44                 :          0 :                 chandef->width = NL80211_CHAN_WIDTH_40;
      45                 :          0 :                 chandef->center_freq1 = chan->center_freq + 10;
      46                 :          0 :                 break;
      47                 :            :         case NL80211_CHAN_HT40MINUS:
      48                 :          0 :                 chandef->width = NL80211_CHAN_WIDTH_40;
      49                 :          0 :                 chandef->center_freq1 = chan->center_freq - 10;
      50                 :          0 :                 break;
      51                 :            :         default:
      52                 :          0 :                 WARN_ON(1);
      53                 :            :         }
      54                 :            : }
      55                 :            : EXPORT_SYMBOL(cfg80211_chandef_create);
      56                 :            : 
      57                 :          0 : static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
      58                 :            : {
      59                 :            :         int max_contiguous = 0;
      60                 :            :         int num_of_enabled = 0;
      61                 :            :         int contiguous = 0;
      62                 :            :         int i;
      63                 :            : 
      64   [ #  #  #  # ]:          0 :         if (!chandef->edmg.channels || !chandef->edmg.bw_config)
      65                 :            :                 return false;
      66                 :            : 
      67         [ #  # ]:          0 :         if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
      68                 :            :                 return false;
      69                 :            : 
      70         [ #  # ]:          0 :         for (i = 0; i < 6; i++) {
      71         [ #  # ]:          0 :                 if (chandef->edmg.channels & BIT(i)) {
      72                 :          0 :                         contiguous++;
      73                 :          0 :                         num_of_enabled++;
      74                 :            :                 } else {
      75                 :            :                         contiguous = 0;
      76                 :            :                 }
      77                 :            : 
      78                 :          0 :                 max_contiguous = max(contiguous, max_contiguous);
      79                 :            :         }
      80                 :            :         /* basic verification of edmg configuration according to
      81                 :            :          * IEEE P802.11ay/D4.0 section 9.4.2.251
      82                 :            :          */
      83                 :            :         /* check bw_config against contiguous edmg channels */
      84   [ #  #  #  #  :          0 :         switch (chandef->edmg.bw_config) {
                      # ]
      85                 :            :         case IEEE80211_EDMG_BW_CONFIG_4:
      86                 :            :         case IEEE80211_EDMG_BW_CONFIG_8:
      87                 :            :         case IEEE80211_EDMG_BW_CONFIG_12:
      88         [ #  # ]:          0 :                 if (max_contiguous < 1)
      89                 :            :                         return false;
      90                 :            :                 break;
      91                 :            :         case IEEE80211_EDMG_BW_CONFIG_5:
      92                 :            :         case IEEE80211_EDMG_BW_CONFIG_9:
      93                 :            :         case IEEE80211_EDMG_BW_CONFIG_13:
      94         [ #  # ]:          0 :                 if (max_contiguous < 2)
      95                 :            :                         return false;
      96                 :            :                 break;
      97                 :            :         case IEEE80211_EDMG_BW_CONFIG_6:
      98                 :            :         case IEEE80211_EDMG_BW_CONFIG_10:
      99                 :            :         case IEEE80211_EDMG_BW_CONFIG_14:
     100         [ #  # ]:          0 :                 if (max_contiguous < 3)
     101                 :            :                         return false;
     102                 :            :                 break;
     103                 :            :         case IEEE80211_EDMG_BW_CONFIG_7:
     104                 :            :         case IEEE80211_EDMG_BW_CONFIG_11:
     105                 :            :         case IEEE80211_EDMG_BW_CONFIG_15:
     106         [ #  # ]:          0 :                 if (max_contiguous < 4)
     107                 :            :                         return false;
     108                 :            :                 break;
     109                 :            : 
     110                 :            :         default:
     111                 :            :                 return false;
     112                 :            :         }
     113                 :            : 
     114                 :            :         /* check bw_config against aggregated (non contiguous) edmg channels */
     115   [ #  #  #  # ]:          0 :         switch (chandef->edmg.bw_config) {
     116                 :            :         case IEEE80211_EDMG_BW_CONFIG_4:
     117                 :            :         case IEEE80211_EDMG_BW_CONFIG_5:
     118                 :            :         case IEEE80211_EDMG_BW_CONFIG_6:
     119                 :            :         case IEEE80211_EDMG_BW_CONFIG_7:
     120                 :            :                 break;
     121                 :            :         case IEEE80211_EDMG_BW_CONFIG_8:
     122                 :            :         case IEEE80211_EDMG_BW_CONFIG_9:
     123                 :            :         case IEEE80211_EDMG_BW_CONFIG_10:
     124                 :            :         case IEEE80211_EDMG_BW_CONFIG_11:
     125         [ #  # ]:          0 :                 if (num_of_enabled < 2)
     126                 :            :                         return false;
     127                 :            :                 break;
     128                 :            :         case IEEE80211_EDMG_BW_CONFIG_12:
     129                 :            :         case IEEE80211_EDMG_BW_CONFIG_13:
     130                 :            :         case IEEE80211_EDMG_BW_CONFIG_14:
     131                 :            :         case IEEE80211_EDMG_BW_CONFIG_15:
     132         [ #  # ]:          0 :                 if (num_of_enabled < 4 || max_contiguous < 2)
     133                 :            :                         return false;
     134                 :            :                 break;
     135                 :            :         default:
     136                 :            :                 return false;
     137                 :            :         }
     138                 :            : 
     139                 :          0 :         return true;
     140                 :            : }
     141                 :            : 
     142                 :          0 : bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
     143                 :            : {
     144                 :            :         u32 control_freq;
     145                 :            : 
     146         [ #  # ]:          0 :         if (!chandef->chan)
     147                 :            :                 return false;
     148                 :            : 
     149                 :          0 :         control_freq = chandef->chan->center_freq;
     150                 :            : 
     151   [ #  #  #  #  :          0 :         switch (chandef->width) {
                   #  # ]
     152                 :            :         case NL80211_CHAN_WIDTH_5:
     153                 :            :         case NL80211_CHAN_WIDTH_10:
     154                 :            :         case NL80211_CHAN_WIDTH_20:
     155                 :            :         case NL80211_CHAN_WIDTH_20_NOHT:
     156         [ #  # ]:          0 :                 if (chandef->center_freq1 != control_freq)
     157                 :            :                         return false;
     158         [ #  # ]:          0 :                 if (chandef->center_freq2)
     159                 :            :                         return false;
     160                 :            :                 break;
     161                 :            :         case NL80211_CHAN_WIDTH_40:
     162   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 != control_freq + 10 &&
     163                 :          0 :                     chandef->center_freq1 != control_freq - 10)
     164                 :            :                         return false;
     165         [ #  # ]:          0 :                 if (chandef->center_freq2)
     166                 :            :                         return false;
     167                 :            :                 break;
     168                 :            :         case NL80211_CHAN_WIDTH_80P80:
     169   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 != control_freq + 30 &&
     170         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq + 10 &&
     171         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq - 10 &&
     172                 :          0 :                     chandef->center_freq1 != control_freq - 30)
     173                 :            :                         return false;
     174         [ #  # ]:          0 :                 if (!chandef->center_freq2)
     175                 :            :                         return false;
     176                 :            :                 /* adjacent is not allowed -- that's a 160 MHz channel */
     177   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
     178                 :          0 :                     chandef->center_freq2 - chandef->center_freq1 == 80)
     179                 :            :                         return false;
     180                 :            :                 break;
     181                 :            :         case NL80211_CHAN_WIDTH_80:
     182   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 != control_freq + 30 &&
     183         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq + 10 &&
     184         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq - 10 &&
     185                 :          0 :                     chandef->center_freq1 != control_freq - 30)
     186                 :            :                         return false;
     187         [ #  # ]:          0 :                 if (chandef->center_freq2)
     188                 :            :                         return false;
     189                 :            :                 break;
     190                 :            :         case NL80211_CHAN_WIDTH_160:
     191   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 != control_freq + 70 &&
     192         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq + 50 &&
     193         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq + 30 &&
     194         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq + 10 &&
     195         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq - 10 &&
     196         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq - 30 &&
     197         [ #  # ]:          0 :                     chandef->center_freq1 != control_freq - 50 &&
     198                 :          0 :                     chandef->center_freq1 != control_freq - 70)
     199                 :            :                         return false;
     200         [ #  # ]:          0 :                 if (chandef->center_freq2)
     201                 :            :                         return false;
     202                 :            :                 break;
     203                 :            :         default:
     204                 :            :                 return false;
     205                 :            :         }
     206                 :            : 
     207                 :            :         /* channel 14 is only for IEEE 802.11b */
     208   [ #  #  #  # ]:          0 :         if (chandef->center_freq1 == 2484 &&
     209                 :            :             chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
     210                 :            :                 return false;
     211                 :            : 
     212   [ #  #  #  # ]:          0 :         if (cfg80211_chandef_is_edmg(chandef) &&
     213                 :          0 :             !cfg80211_edmg_chandef_valid(chandef))
     214                 :            :                 return false;
     215                 :            : 
     216                 :          0 :         return true;
     217                 :            : }
     218                 :            : EXPORT_SYMBOL(cfg80211_chandef_valid);
     219                 :            : 
     220                 :          0 : static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
     221                 :            :                                   u32 *pri40, u32 *pri80)
     222                 :            : {
     223                 :            :         int tmp;
     224                 :            : 
     225   [ #  #  #  # ]:          0 :         switch (c->width) {
     226                 :            :         case NL80211_CHAN_WIDTH_40:
     227                 :          0 :                 *pri40 = c->center_freq1;
     228                 :          0 :                 *pri80 = 0;
     229                 :          0 :                 break;
     230                 :            :         case NL80211_CHAN_WIDTH_80:
     231                 :            :         case NL80211_CHAN_WIDTH_80P80:
     232                 :          0 :                 *pri80 = c->center_freq1;
     233                 :            :                 /* n_P20 */
     234                 :          0 :                 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
     235                 :            :                 /* n_P40 */
     236                 :          0 :                 tmp /= 2;
     237                 :            :                 /* freq_P40 */
     238                 :          0 :                 *pri40 = c->center_freq1 - 20 + 40 * tmp;
     239                 :          0 :                 break;
     240                 :            :         case NL80211_CHAN_WIDTH_160:
     241                 :            :                 /* n_P20 */
     242                 :          0 :                 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
     243                 :            :                 /* n_P40 */
     244                 :          0 :                 tmp /= 2;
     245                 :            :                 /* freq_P40 */
     246                 :          0 :                 *pri40 = c->center_freq1 - 60 + 40 * tmp;
     247                 :            :                 /* n_P80 */
     248                 :          0 :                 tmp /= 2;
     249                 :          0 :                 *pri80 = c->center_freq1 - 40 + 80 * tmp;
     250                 :          0 :                 break;
     251                 :            :         default:
     252         [ #  # ]:          0 :                 WARN_ON_ONCE(1);
     253                 :            :         }
     254                 :          0 : }
     255                 :            : 
     256                 :          0 : static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
     257                 :            : {
     258                 :            :         int width;
     259                 :            : 
     260   [ #  #  #  #  :          0 :         switch (c->width) {
                #  #  # ]
     261                 :            :         case NL80211_CHAN_WIDTH_5:
     262                 :            :                 width = 5;
     263                 :            :                 break;
     264                 :            :         case NL80211_CHAN_WIDTH_10:
     265                 :            :                 width = 10;
     266                 :          0 :                 break;
     267                 :            :         case NL80211_CHAN_WIDTH_20:
     268                 :            :         case NL80211_CHAN_WIDTH_20_NOHT:
     269                 :            :                 width = 20;
     270                 :          0 :                 break;
     271                 :            :         case NL80211_CHAN_WIDTH_40:
     272                 :            :                 width = 40;
     273                 :          0 :                 break;
     274                 :            :         case NL80211_CHAN_WIDTH_80P80:
     275                 :            :         case NL80211_CHAN_WIDTH_80:
     276                 :            :                 width = 80;
     277                 :          0 :                 break;
     278                 :            :         case NL80211_CHAN_WIDTH_160:
     279                 :            :                 width = 160;
     280                 :          0 :                 break;
     281                 :            :         default:
     282         [ #  # ]:          0 :                 WARN_ON_ONCE(1);
     283                 :            :                 return -1;
     284                 :            :         }
     285                 :          0 :         return width;
     286                 :            : }
     287                 :            : 
     288                 :            : const struct cfg80211_chan_def *
     289                 :          0 : cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
     290                 :            :                             const struct cfg80211_chan_def *c2)
     291                 :            : {
     292                 :            :         u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
     293                 :            : 
     294                 :            :         /* If they are identical, return */
     295         [ #  # ]:          0 :         if (cfg80211_chandef_identical(c1, c2))
     296                 :            :                 return c1;
     297                 :            : 
     298                 :            :         /* otherwise, must have same control channel */
     299         [ #  # ]:          0 :         if (c1->chan != c2->chan)
     300                 :            :                 return NULL;
     301                 :            : 
     302                 :            :         /*
     303                 :            :          * If they have the same width, but aren't identical,
     304                 :            :          * then they can't be compatible.
     305                 :            :          */
     306         [ #  # ]:          0 :         if (c1->width == c2->width)
     307                 :            :                 return NULL;
     308                 :            : 
     309                 :            :         /*
     310                 :            :          * can't be compatible if one of them is 5 or 10 MHz,
     311                 :            :          * but they don't have the same width.
     312                 :            :          */
     313         [ #  # ]:          0 :         if (c1->width == NL80211_CHAN_WIDTH_5 ||
     314         [ #  # ]:          0 :             c1->width == NL80211_CHAN_WIDTH_10 ||
     315         [ #  # ]:          0 :             c2->width == NL80211_CHAN_WIDTH_5 ||
     316                 :            :             c2->width == NL80211_CHAN_WIDTH_10)
     317                 :            :                 return NULL;
     318                 :            : 
     319         [ #  # ]:          0 :         if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
     320                 :            :             c1->width == NL80211_CHAN_WIDTH_20)
     321                 :            :                 return c2;
     322                 :            : 
     323         [ #  # ]:          0 :         if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
     324                 :            :             c2->width == NL80211_CHAN_WIDTH_20)
     325                 :            :                 return c1;
     326                 :            : 
     327                 :          0 :         chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
     328                 :          0 :         chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
     329                 :            : 
     330         [ #  # ]:          0 :         if (c1_pri40 != c2_pri40)
     331                 :            :                 return NULL;
     332                 :            : 
     333   [ #  #  #  #  :          0 :         WARN_ON(!c1_pri80 && !c2_pri80);
                   #  # ]
     334   [ #  #  #  #  :          0 :         if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
                   #  # ]
     335                 :            :                 return NULL;
     336                 :            : 
     337         [ #  # ]:          0 :         if (c1->width > c2->width)
     338                 :            :                 return c1;
     339                 :          0 :         return c2;
     340                 :            : }
     341                 :            : EXPORT_SYMBOL(cfg80211_chandef_compatible);
     342                 :            : 
     343                 :          0 : static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
     344                 :            :                                          u32 bandwidth,
     345                 :            :                                          enum nl80211_dfs_state dfs_state)
     346                 :            : {
     347                 :            :         struct ieee80211_channel *c;
     348                 :            :         u32 freq;
     349                 :            : 
     350         [ #  # ]:          0 :         for (freq = center_freq - bandwidth/2 + 10;
     351                 :          0 :              freq <= center_freq + bandwidth/2 - 10;
     352                 :          0 :              freq += 20) {
     353                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     354   [ #  #  #  # ]:          0 :                 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
     355                 :          0 :                         continue;
     356                 :            : 
     357                 :          0 :                 c->dfs_state = dfs_state;
     358                 :          0 :                 c->dfs_state_entered = jiffies;
     359                 :            :         }
     360                 :          0 : }
     361                 :            : 
     362                 :          0 : void cfg80211_set_dfs_state(struct wiphy *wiphy,
     363                 :            :                             const struct cfg80211_chan_def *chandef,
     364                 :            :                             enum nl80211_dfs_state dfs_state)
     365                 :            : {
     366                 :            :         int width;
     367                 :            : 
     368   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     369                 :            :                 return;
     370                 :            : 
     371                 :          0 :         width = cfg80211_chandef_get_width(chandef);
     372         [ #  # ]:          0 :         if (width < 0)
     373                 :            :                 return;
     374                 :            : 
     375                 :          0 :         cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
     376                 :            :                                      width, dfs_state);
     377                 :            : 
     378         [ #  # ]:          0 :         if (!chandef->center_freq2)
     379                 :            :                 return;
     380                 :          0 :         cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
     381                 :            :                                      width, dfs_state);
     382                 :            : }
     383                 :            : 
     384                 :            : static u32 cfg80211_get_start_freq(u32 center_freq,
     385                 :            :                                    u32 bandwidth)
     386                 :            : {
     387                 :            :         u32 start_freq;
     388                 :            : 
     389   [ #  #  #  #  :          0 :         if (bandwidth <= 20)
          #  #  #  #  #  
                      # ]
     390                 :            :                 start_freq = center_freq;
     391                 :            :         else
     392                 :          0 :                 start_freq = center_freq - bandwidth/2 + 10;
     393                 :            : 
     394                 :            :         return start_freq;
     395                 :            : }
     396                 :            : 
     397                 :            : static u32 cfg80211_get_end_freq(u32 center_freq,
     398                 :            :                                  u32 bandwidth)
     399                 :            : {
     400                 :            :         u32 end_freq;
     401                 :            : 
     402   [ #  #  #  #  :          0 :         if (bandwidth <= 20)
          #  #  #  #  #  
                      # ]
     403                 :            :                 end_freq = center_freq;
     404                 :            :         else
     405                 :          0 :                 end_freq = center_freq + bandwidth/2 - 10;
     406                 :            : 
     407                 :            :         return end_freq;
     408                 :            : }
     409                 :            : 
     410                 :          0 : static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
     411                 :            :                                             u32 center_freq,
     412                 :            :                                             u32 bandwidth)
     413                 :            : {
     414                 :            :         struct ieee80211_channel *c;
     415                 :            :         u32 freq, start_freq, end_freq;
     416                 :            : 
     417                 :            :         start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
     418                 :            :         end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
     419                 :            : 
     420         [ #  # ]:          0 :         for (freq = start_freq; freq <= end_freq; freq += 20) {
     421                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     422         [ #  # ]:          0 :                 if (!c)
     423                 :            :                         return -EINVAL;
     424                 :            : 
     425         [ #  # ]:          0 :                 if (c->flags & IEEE80211_CHAN_RADAR)
     426                 :            :                         return 1;
     427                 :            :         }
     428                 :            :         return 0;
     429                 :            : }
     430                 :            : 
     431                 :            : 
     432                 :          0 : int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
     433                 :            :                                   const struct cfg80211_chan_def *chandef,
     434                 :            :                                   enum nl80211_iftype iftype)
     435                 :            : {
     436                 :            :         int width;
     437                 :            :         int ret;
     438                 :            : 
     439   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     440                 :            :                 return -EINVAL;
     441                 :            : 
     442      [ #  #  # ]:          0 :         switch (iftype) {
     443                 :            :         case NL80211_IFTYPE_ADHOC:
     444                 :            :         case NL80211_IFTYPE_AP:
     445                 :            :         case NL80211_IFTYPE_P2P_GO:
     446                 :            :         case NL80211_IFTYPE_MESH_POINT:
     447                 :          0 :                 width = cfg80211_chandef_get_width(chandef);
     448         [ #  # ]:          0 :                 if (width < 0)
     449                 :            :                         return -EINVAL;
     450                 :            : 
     451                 :          0 :                 ret = cfg80211_get_chans_dfs_required(wiphy,
     452                 :            :                                                       chandef->center_freq1,
     453                 :            :                                                       width);
     454         [ #  # ]:          0 :                 if (ret < 0)
     455                 :            :                         return ret;
     456         [ #  # ]:          0 :                 else if (ret > 0)
     457                 :          0 :                         return BIT(chandef->width);
     458                 :            : 
     459         [ #  # ]:          0 :                 if (!chandef->center_freq2)
     460                 :            :                         return 0;
     461                 :            : 
     462                 :          0 :                 ret = cfg80211_get_chans_dfs_required(wiphy,
     463                 :            :                                                       chandef->center_freq2,
     464                 :            :                                                       width);
     465         [ #  # ]:          0 :                 if (ret < 0)
     466                 :            :                         return ret;
     467         [ #  # ]:          0 :                 else if (ret > 0)
     468                 :          0 :                         return BIT(chandef->width);
     469                 :            : 
     470                 :            :                 break;
     471                 :            :         case NL80211_IFTYPE_STATION:
     472                 :            :         case NL80211_IFTYPE_OCB:
     473                 :            :         case NL80211_IFTYPE_P2P_CLIENT:
     474                 :            :         case NL80211_IFTYPE_MONITOR:
     475                 :            :         case NL80211_IFTYPE_AP_VLAN:
     476                 :            :         case NL80211_IFTYPE_WDS:
     477                 :            :         case NL80211_IFTYPE_P2P_DEVICE:
     478                 :            :         case NL80211_IFTYPE_NAN:
     479                 :            :                 break;
     480                 :            :         case NL80211_IFTYPE_UNSPECIFIED:
     481                 :            :         case NUM_NL80211_IFTYPES:
     482                 :          0 :                 WARN_ON(1);
     483                 :            :         }
     484                 :            : 
     485                 :            :         return 0;
     486                 :            : }
     487                 :            : EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
     488                 :            : 
     489                 :          0 : static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
     490                 :            :                                          u32 center_freq,
     491                 :            :                                          u32 bandwidth)
     492                 :            : {
     493                 :            :         struct ieee80211_channel *c;
     494                 :            :         u32 freq, start_freq, end_freq;
     495                 :            :         int count = 0;
     496                 :            : 
     497                 :            :         start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
     498                 :            :         end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
     499                 :            : 
     500                 :            :         /*
     501                 :            :          * Check entire range of channels for the bandwidth.
     502                 :            :          * Check all channels are DFS channels (DFS_USABLE or
     503                 :            :          * DFS_AVAILABLE). Return number of usable channels
     504                 :            :          * (require CAC). Allow DFS and non-DFS channel mix.
     505                 :            :          */
     506         [ #  # ]:          0 :         for (freq = start_freq; freq <= end_freq; freq += 20) {
     507                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     508         [ #  # ]:          0 :                 if (!c)
     509                 :            :                         return -EINVAL;
     510                 :            : 
     511         [ #  # ]:          0 :                 if (c->flags & IEEE80211_CHAN_DISABLED)
     512                 :            :                         return -EINVAL;
     513                 :            : 
     514         [ #  # ]:          0 :                 if (c->flags & IEEE80211_CHAN_RADAR) {
     515         [ #  # ]:          0 :                         if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
     516                 :            :                                 return -EINVAL;
     517                 :            : 
     518         [ #  # ]:          0 :                         if (c->dfs_state == NL80211_DFS_USABLE)
     519                 :          0 :                                 count++;
     520                 :            :                 }
     521                 :            :         }
     522                 :            : 
     523                 :          0 :         return count;
     524                 :            : }
     525                 :            : 
     526                 :          0 : bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
     527                 :            :                                  const struct cfg80211_chan_def *chandef)
     528                 :            : {
     529                 :            :         int width;
     530                 :            :         int r1, r2 = 0;
     531                 :            : 
     532   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     533                 :            :                 return false;
     534                 :            : 
     535                 :          0 :         width = cfg80211_chandef_get_width(chandef);
     536         [ #  # ]:          0 :         if (width < 0)
     537                 :            :                 return false;
     538                 :            : 
     539                 :          0 :         r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
     540                 :            :                                           width);
     541                 :            : 
     542         [ #  # ]:          0 :         if (r1 < 0)
     543                 :            :                 return false;
     544                 :            : 
     545         [ #  # ]:          0 :         switch (chandef->width) {
     546                 :            :         case NL80211_CHAN_WIDTH_80P80:
     547         [ #  # ]:          0 :                 WARN_ON(!chandef->center_freq2);
     548                 :          0 :                 r2 = cfg80211_get_chans_dfs_usable(wiphy,
     549                 :            :                                                    chandef->center_freq2,
     550                 :            :                                                    width);
     551         [ #  # ]:          0 :                 if (r2 < 0)
     552                 :            :                         return false;
     553                 :            :                 break;
     554                 :            :         default:
     555         [ #  # ]:          0 :                 WARN_ON(chandef->center_freq2);
     556                 :            :                 break;
     557                 :            :         }
     558                 :            : 
     559                 :          0 :         return (r1 + r2 > 0);
     560                 :            : }
     561                 :            : 
     562                 :            : /*
     563                 :            :  * Checks if center frequency of chan falls with in the bandwidth
     564                 :            :  * range of chandef.
     565                 :            :  */
     566                 :          0 : bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
     567                 :            :                           struct ieee80211_channel *chan)
     568                 :            : {
     569                 :            :         int width;
     570                 :            :         u32 freq;
     571                 :            : 
     572         [ #  # ]:          0 :         if (chandef->chan->center_freq == chan->center_freq)
     573                 :            :                 return true;
     574                 :            : 
     575                 :          0 :         width = cfg80211_chandef_get_width(chandef);
     576         [ #  # ]:          0 :         if (width <= 20)
     577                 :            :                 return false;
     578                 :            : 
     579         [ #  # ]:          0 :         for (freq = chandef->center_freq1 - width / 2 + 10;
     580                 :          0 :              freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
     581         [ #  # ]:          0 :                 if (chan->center_freq == freq)
     582                 :            :                         return true;
     583                 :            :         }
     584                 :            : 
     585         [ #  # ]:          0 :         if (!chandef->center_freq2)
     586                 :            :                 return false;
     587                 :            : 
     588         [ #  # ]:          0 :         for (freq = chandef->center_freq2 - width / 2 + 10;
     589                 :          0 :              freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
     590         [ #  # ]:          0 :                 if (chan->center_freq == freq)
     591                 :            :                         return true;
     592                 :            :         }
     593                 :            : 
     594                 :            :         return false;
     595                 :            : }
     596                 :            : 
     597                 :          0 : bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
     598                 :            : {
     599                 :            :         bool active = false;
     600                 :            : 
     601                 :            :         ASSERT_WDEV_LOCK(wdev);
     602                 :            : 
     603         [ #  # ]:          0 :         if (!wdev->chandef.chan)
     604                 :            :                 return false;
     605                 :            : 
     606   [ #  #  #  #  :          0 :         switch (wdev->iftype) {
                      # ]
     607                 :            :         case NL80211_IFTYPE_AP:
     608                 :            :         case NL80211_IFTYPE_P2P_GO:
     609                 :          0 :                 active = wdev->beacon_interval != 0;
     610                 :          0 :                 break;
     611                 :            :         case NL80211_IFTYPE_ADHOC:
     612                 :          0 :                 active = wdev->ssid_len != 0;
     613                 :          0 :                 break;
     614                 :            :         case NL80211_IFTYPE_MESH_POINT:
     615                 :          0 :                 active = wdev->mesh_id_len != 0;
     616                 :          0 :                 break;
     617                 :            :         case NL80211_IFTYPE_STATION:
     618                 :            :         case NL80211_IFTYPE_OCB:
     619                 :            :         case NL80211_IFTYPE_P2P_CLIENT:
     620                 :            :         case NL80211_IFTYPE_MONITOR:
     621                 :            :         case NL80211_IFTYPE_AP_VLAN:
     622                 :            :         case NL80211_IFTYPE_WDS:
     623                 :            :         case NL80211_IFTYPE_P2P_DEVICE:
     624                 :            :         /* Can NAN type be considered as beaconing interface? */
     625                 :            :         case NL80211_IFTYPE_NAN:
     626                 :            :                 break;
     627                 :            :         case NL80211_IFTYPE_UNSPECIFIED:
     628                 :            :         case NUM_NL80211_IFTYPES:
     629                 :          0 :                 WARN_ON(1);
     630                 :            :         }
     631                 :            : 
     632                 :          0 :         return active;
     633                 :            : }
     634                 :            : 
     635                 :          0 : static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
     636                 :            :                                         struct ieee80211_channel *chan)
     637                 :            : {
     638                 :            :         struct wireless_dev *wdev;
     639                 :            : 
     640         [ #  # ]:          0 :         list_for_each_entry(wdev, &wiphy->wdev_list, list) {
     641                 :            :                 wdev_lock(wdev);
     642         [ #  # ]:          0 :                 if (!cfg80211_beaconing_iface_active(wdev)) {
     643                 :            :                         wdev_unlock(wdev);
     644                 :          0 :                         continue;
     645                 :            :                 }
     646                 :            : 
     647         [ #  # ]:          0 :                 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
     648                 :            :                         wdev_unlock(wdev);
     649                 :          0 :                         return true;
     650                 :            :                 }
     651                 :            :                 wdev_unlock(wdev);
     652                 :            :         }
     653                 :            : 
     654                 :            :         return false;
     655                 :            : }
     656                 :            : 
     657                 :          0 : bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
     658                 :            :                                   struct ieee80211_channel *chan)
     659                 :            : {
     660                 :            :         struct cfg80211_registered_device *rdev;
     661                 :            : 
     662   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
     663                 :            : 
     664         [ #  # ]:          0 :         if (!(chan->flags & IEEE80211_CHAN_RADAR))
     665                 :            :                 return false;
     666                 :            : 
     667         [ #  # ]:          0 :         list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
     668         [ #  # ]:          0 :                 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
     669                 :          0 :                         continue;
     670                 :            : 
     671         [ #  # ]:          0 :                 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
     672                 :            :                         return true;
     673                 :            :         }
     674                 :            : 
     675                 :            :         return false;
     676                 :            : }
     677                 :            : 
     678                 :          0 : static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
     679                 :            :                                              u32 center_freq,
     680                 :            :                                              u32 bandwidth)
     681                 :            : {
     682                 :            :         struct ieee80211_channel *c;
     683                 :            :         u32 freq, start_freq, end_freq;
     684                 :            :         bool dfs_offload;
     685                 :            : 
     686                 :            :         dfs_offload = wiphy_ext_feature_isset(wiphy,
     687                 :            :                                               NL80211_EXT_FEATURE_DFS_OFFLOAD);
     688                 :            : 
     689                 :            :         start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
     690                 :            :         end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
     691                 :            : 
     692                 :            :         /*
     693                 :            :          * Check entire range of channels for the bandwidth.
     694                 :            :          * If any channel in between is disabled or has not
     695                 :            :          * had gone through CAC return false
     696                 :            :          */
     697         [ #  # ]:          0 :         for (freq = start_freq; freq <= end_freq; freq += 20) {
     698                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     699         [ #  # ]:          0 :                 if (!c)
     700                 :            :                         return false;
     701                 :            : 
     702         [ #  # ]:          0 :                 if (c->flags & IEEE80211_CHAN_DISABLED)
     703                 :            :                         return false;
     704                 :            : 
     705   [ #  #  #  # ]:          0 :                 if ((c->flags & IEEE80211_CHAN_RADAR) &&
     706         [ #  # ]:          0 :                     (c->dfs_state != NL80211_DFS_AVAILABLE) &&
     707         [ #  # ]:          0 :                     !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
     708                 :            :                         return false;
     709                 :            :         }
     710                 :            : 
     711                 :            :         return true;
     712                 :            : }
     713                 :            : 
     714                 :          0 : static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
     715                 :            :                                 const struct cfg80211_chan_def *chandef)
     716                 :            : {
     717                 :            :         int width;
     718                 :            :         int r;
     719                 :            : 
     720   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     721                 :            :                 return false;
     722                 :            : 
     723                 :          0 :         width = cfg80211_chandef_get_width(chandef);
     724         [ #  # ]:          0 :         if (width < 0)
     725                 :            :                 return false;
     726                 :            : 
     727                 :          0 :         r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
     728                 :            :                                              width);
     729                 :            : 
     730                 :            :         /* If any of channels unavailable for cf1 just return */
     731         [ #  # ]:          0 :         if (!r)
     732                 :            :                 return r;
     733                 :            : 
     734         [ #  # ]:          0 :         switch (chandef->width) {
     735                 :            :         case NL80211_CHAN_WIDTH_80P80:
     736         [ #  # ]:          0 :                 WARN_ON(!chandef->center_freq2);
     737                 :          0 :                 r = cfg80211_get_chans_dfs_available(wiphy,
     738                 :            :                                                      chandef->center_freq2,
     739                 :            :                                                      width);
     740                 :          0 :                 break;
     741                 :            :         default:
     742         [ #  # ]:          0 :                 WARN_ON(chandef->center_freq2);
     743                 :            :                 break;
     744                 :            :         }
     745                 :            : 
     746                 :          0 :         return r;
     747                 :            : }
     748                 :            : 
     749                 :          0 : static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
     750                 :            :                                                     u32 center_freq,
     751                 :            :                                                     u32 bandwidth)
     752                 :            : {
     753                 :            :         struct ieee80211_channel *c;
     754                 :            :         u32 start_freq, end_freq, freq;
     755                 :            :         unsigned int dfs_cac_ms = 0;
     756                 :            : 
     757                 :            :         start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
     758                 :            :         end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
     759                 :            : 
     760         [ #  # ]:          0 :         for (freq = start_freq; freq <= end_freq; freq += 20) {
     761                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     762         [ #  # ]:          0 :                 if (!c)
     763                 :            :                         return 0;
     764                 :            : 
     765         [ #  # ]:          0 :                 if (c->flags & IEEE80211_CHAN_DISABLED)
     766                 :            :                         return 0;
     767                 :            : 
     768         [ #  # ]:          0 :                 if (!(c->flags & IEEE80211_CHAN_RADAR))
     769                 :          0 :                         continue;
     770                 :            : 
     771         [ #  # ]:          0 :                 if (c->dfs_cac_ms > dfs_cac_ms)
     772                 :            :                         dfs_cac_ms = c->dfs_cac_ms;
     773                 :            :         }
     774                 :            : 
     775                 :          0 :         return dfs_cac_ms;
     776                 :            : }
     777                 :            : 
     778                 :            : unsigned int
     779                 :          0 : cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
     780                 :            :                               const struct cfg80211_chan_def *chandef)
     781                 :            : {
     782                 :            :         int width;
     783                 :            :         unsigned int t1 = 0, t2 = 0;
     784                 :            : 
     785   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     786                 :            :                 return 0;
     787                 :            : 
     788                 :          0 :         width = cfg80211_chandef_get_width(chandef);
     789         [ #  # ]:          0 :         if (width < 0)
     790                 :            :                 return 0;
     791                 :            : 
     792                 :          0 :         t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
     793                 :            :                                              chandef->center_freq1,
     794                 :            :                                              width);
     795                 :            : 
     796         [ #  # ]:          0 :         if (!chandef->center_freq2)
     797                 :            :                 return t1;
     798                 :            : 
     799                 :          0 :         t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
     800                 :            :                                              chandef->center_freq2,
     801                 :            :                                              width);
     802                 :            : 
     803                 :          0 :         return max(t1, t2);
     804                 :            : }
     805                 :            : 
     806                 :          0 : static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
     807                 :            :                                         u32 center_freq, u32 bandwidth,
     808                 :            :                                         u32 prohibited_flags)
     809                 :            : {
     810                 :            :         struct ieee80211_channel *c;
     811                 :            :         u32 freq, start_freq, end_freq;
     812                 :            : 
     813                 :            :         start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
     814                 :            :         end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
     815                 :            : 
     816         [ #  # ]:          0 :         for (freq = start_freq; freq <= end_freq; freq += 20) {
     817                 :          0 :                 c = ieee80211_get_channel(wiphy, freq);
     818   [ #  #  #  # ]:          0 :                 if (!c || c->flags & prohibited_flags)
     819                 :            :                         return false;
     820                 :            :         }
     821                 :            : 
     822                 :            :         return true;
     823                 :            : }
     824                 :            : 
     825                 :            : /* check if the operating channels are valid and supported */
     826                 :          0 : static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
     827                 :            :                                  enum ieee80211_edmg_bw_config edmg_bw_config,
     828                 :            :                                  int primary_channel,
     829                 :            :                                  struct ieee80211_edmg *edmg_cap)
     830                 :            : {
     831                 :            :         struct ieee80211_channel *chan;
     832                 :            :         int i, freq;
     833                 :            :         int channels_counter = 0;
     834                 :            : 
     835         [ #  # ]:          0 :         if (!edmg_channels && !edmg_bw_config)
     836                 :            :                 return true;
     837                 :            : 
     838         [ #  # ]:          0 :         if ((!edmg_channels && edmg_bw_config) ||
     839                 :            :             (edmg_channels && !edmg_bw_config))
     840                 :            :                 return false;
     841                 :            : 
     842         [ #  # ]:          0 :         if (!(edmg_channels & BIT(primary_channel - 1)))
     843                 :            :                 return false;
     844                 :            : 
     845                 :            :         /* 60GHz channels 1..6 */
     846         [ #  # ]:          0 :         for (i = 0; i < 6; i++) {
     847         [ #  # ]:          0 :                 if (!(edmg_channels & BIT(i)))
     848                 :          0 :                         continue;
     849                 :            : 
     850         [ #  # ]:          0 :                 if (!(edmg_cap->channels & BIT(i)))
     851                 :            :                         return false;
     852                 :            : 
     853                 :          0 :                 channels_counter++;
     854                 :            : 
     855                 :          0 :                 freq = ieee80211_channel_to_frequency(i + 1,
     856                 :            :                                                       NL80211_BAND_60GHZ);
     857                 :          0 :                 chan = ieee80211_get_channel(wiphy, freq);
     858   [ #  #  #  # ]:          0 :                 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
     859                 :            :                         return false;
     860                 :            :         }
     861                 :            : 
     862                 :            :         /* IEEE802.11 allows max 4 channels */
     863         [ #  # ]:          0 :         if (channels_counter > 4)
     864                 :            :                 return false;
     865                 :            : 
     866                 :            :         /* check bw_config is a subset of what driver supports
     867                 :            :          * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
     868                 :            :          */
     869         [ #  # ]:          0 :         if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
     870                 :            :                 return false;
     871                 :            : 
     872         [ #  # ]:          0 :         if (edmg_bw_config > edmg_cap->bw_config)
     873                 :            :                 return false;
     874                 :            : 
     875                 :          0 :         return true;
     876                 :            : }
     877                 :            : 
     878                 :          0 : bool cfg80211_chandef_usable(struct wiphy *wiphy,
     879                 :            :                              const struct cfg80211_chan_def *chandef,
     880                 :            :                              u32 prohibited_flags)
     881                 :            : {
     882                 :            :         struct ieee80211_sta_ht_cap *ht_cap;
     883                 :            :         struct ieee80211_sta_vht_cap *vht_cap;
     884                 :            :         struct ieee80211_edmg *edmg_cap;
     885                 :            :         u32 width, control_freq, cap;
     886                 :            : 
     887   [ #  #  #  # ]:          0 :         if (WARN_ON(!cfg80211_chandef_valid(chandef)))
     888                 :            :                 return false;
     889                 :            : 
     890                 :          0 :         ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
     891                 :            :         vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
     892                 :          0 :         edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
     893                 :            : 
     894   [ #  #  #  # ]:          0 :         if (edmg_cap->channels &&
     895                 :          0 :             !cfg80211_edmg_usable(wiphy,
     896                 :            :                                   chandef->edmg.channels,
     897                 :            :                                   chandef->edmg.bw_config,
     898                 :          0 :                                   chandef->chan->hw_value,
     899                 :            :                                   edmg_cap))
     900                 :            :                 return false;
     901                 :            : 
     902                 :          0 :         control_freq = chandef->chan->center_freq;
     903                 :            : 
     904   [ #  #  #  #  :          0 :         switch (chandef->width) {
             #  #  #  #  
                      # ]
     905                 :            :         case NL80211_CHAN_WIDTH_5:
     906                 :            :                 width = 5;
     907                 :            :                 break;
     908                 :            :         case NL80211_CHAN_WIDTH_10:
     909                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
     910                 :            :                 width = 10;
     911                 :          0 :                 break;
     912                 :            :         case NL80211_CHAN_WIDTH_20:
     913         [ #  # ]:          0 :                 if (!ht_cap->ht_supported)
     914                 :            :                         return false;
     915                 :            :                 /* fall through */
     916                 :            :         case NL80211_CHAN_WIDTH_20_NOHT:
     917                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
     918                 :            :                 width = 20;
     919                 :          0 :                 break;
     920                 :            :         case NL80211_CHAN_WIDTH_40:
     921                 :            :                 width = 40;
     922         [ #  # ]:          0 :                 if (!ht_cap->ht_supported)
     923                 :            :                         return false;
     924         [ #  # ]:          0 :                 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
     925                 :            :                     ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
     926                 :            :                         return false;
     927   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 < control_freq &&
     928                 :          0 :                     chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
     929                 :            :                         return false;
     930   [ #  #  #  # ]:          0 :                 if (chandef->center_freq1 > control_freq &&
     931                 :          0 :                     chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
     932                 :            :                         return false;
     933                 :            :                 break;
     934                 :            :         case NL80211_CHAN_WIDTH_80P80:
     935                 :          0 :                 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
     936         [ #  # ]:          0 :                 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
     937                 :            :                         return false;
     938                 :            :                 /* fall through */
     939                 :            :         case NL80211_CHAN_WIDTH_80:
     940         [ #  # ]:          0 :                 if (!vht_cap->vht_supported)
     941                 :            :                         return false;
     942                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
     943                 :            :                 width = 80;
     944                 :          0 :                 break;
     945                 :            :         case NL80211_CHAN_WIDTH_160:
     946         [ #  # ]:          0 :                 if (!vht_cap->vht_supported)
     947                 :            :                         return false;
     948                 :          0 :                 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
     949         [ #  # ]:          0 :                 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
     950                 :          0 :                     cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
     951                 :            :                         return false;
     952                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
     953                 :            :                 width = 160;
     954                 :          0 :                 break;
     955                 :            :         default:
     956         [ #  # ]:          0 :                 WARN_ON_ONCE(1);
     957                 :            :                 return false;
     958                 :            :         }
     959                 :            : 
     960                 :            :         /*
     961                 :            :          * TODO: What if there are only certain 80/160/80+80 MHz channels
     962                 :            :          *       allowed by the driver, or only certain combinations?
     963                 :            :          *       For 40 MHz the driver can set the NO_HT40 flags, but for
     964                 :            :          *       80/160 MHz and in particular 80+80 MHz this isn't really
     965                 :            :          *       feasible and we only have NO_80MHZ/NO_160MHZ so far but
     966                 :            :          *       no way to cover 80+80 MHz or more complex restrictions.
     967                 :            :          *       Note that such restrictions also need to be advertised to
     968                 :            :          *       userspace, for example for P2P channel selection.
     969                 :            :          */
     970                 :            : 
     971         [ #  # ]:          0 :         if (width > 20)
     972                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
     973                 :            : 
     974                 :            :         /* 5 and 10 MHz are only defined for the OFDM PHY */
     975         [ #  # ]:          0 :         if (width < 20)
     976                 :          0 :                 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
     977                 :            : 
     978                 :            : 
     979         [ #  # ]:          0 :         if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
     980                 :            :                                          width, prohibited_flags))
     981                 :            :                 return false;
     982                 :            : 
     983         [ #  # ]:          0 :         if (!chandef->center_freq2)
     984                 :            :                 return true;
     985                 :          0 :         return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
     986                 :            :                                            width, prohibited_flags);
     987                 :            : }
     988                 :            : EXPORT_SYMBOL(cfg80211_chandef_usable);
     989                 :            : 
     990                 :            : /*
     991                 :            :  * Check if the channel can be used under permissive conditions mandated by
     992                 :            :  * some regulatory bodies, i.e., the channel is marked with
     993                 :            :  * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
     994                 :            :  * associated to an AP on the same channel or on the same UNII band
     995                 :            :  * (assuming that the AP is an authorized master).
     996                 :            :  * In addition allow operation on a channel on which indoor operation is
     997                 :            :  * allowed, iff we are currently operating in an indoor environment.
     998                 :            :  */
     999                 :          0 : static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
    1000                 :            :                                         enum nl80211_iftype iftype,
    1001                 :            :                                         struct ieee80211_channel *chan)
    1002                 :            : {
    1003                 :            :         struct wireless_dev *wdev;
    1004                 :            :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
    1005                 :            : 
    1006   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
    1007                 :            : 
    1008                 :            :         if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
    1009                 :            :             !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
    1010                 :            :                 return false;
    1011                 :            : 
    1012                 :            :         /* only valid for GO and TDLS off-channel (station/p2p-CL) */
    1013                 :            :         if (iftype != NL80211_IFTYPE_P2P_GO &&
    1014                 :            :             iftype != NL80211_IFTYPE_STATION &&
    1015                 :            :             iftype != NL80211_IFTYPE_P2P_CLIENT)
    1016                 :            :                 return false;
    1017                 :            : 
    1018                 :            :         if (regulatory_indoor_allowed() &&
    1019                 :            :             (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
    1020                 :            :                 return true;
    1021                 :            : 
    1022                 :            :         if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
    1023                 :            :                 return false;
    1024                 :            : 
    1025                 :            :         /*
    1026                 :            :          * Generally, it is possible to rely on another device/driver to allow
    1027                 :            :          * the IR concurrent relaxation, however, since the device can further
    1028                 :            :          * enforce the relaxation (by doing a similar verifications as this),
    1029                 :            :          * and thus fail the GO instantiation, consider only the interfaces of
    1030                 :            :          * the current registered device.
    1031                 :            :          */
    1032                 :            :         list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
    1033                 :            :                 struct ieee80211_channel *other_chan = NULL;
    1034                 :            :                 int r1, r2;
    1035                 :            : 
    1036                 :            :                 wdev_lock(wdev);
    1037                 :            :                 if (wdev->iftype == NL80211_IFTYPE_STATION &&
    1038                 :            :                     wdev->current_bss)
    1039                 :            :                         other_chan = wdev->current_bss->pub.channel;
    1040                 :            : 
    1041                 :            :                 /*
    1042                 :            :                  * If a GO already operates on the same GO_CONCURRENT channel,
    1043                 :            :                  * this one (maybe the same one) can beacon as well. We allow
    1044                 :            :                  * the operation even if the station we relied on with
    1045                 :            :                  * GO_CONCURRENT is disconnected now. But then we must make sure
    1046                 :            :                  * we're not outdoor on an indoor-only channel.
    1047                 :            :                  */
    1048                 :            :                 if (iftype == NL80211_IFTYPE_P2P_GO &&
    1049                 :            :                     wdev->iftype == NL80211_IFTYPE_P2P_GO &&
    1050                 :            :                     wdev->beacon_interval &&
    1051                 :            :                     !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
    1052                 :            :                         other_chan = wdev->chandef.chan;
    1053                 :            :                 wdev_unlock(wdev);
    1054                 :            : 
    1055                 :            :                 if (!other_chan)
    1056                 :            :                         continue;
    1057                 :            : 
    1058                 :            :                 if (chan == other_chan)
    1059                 :            :                         return true;
    1060                 :            : 
    1061                 :            :                 if (chan->band != NL80211_BAND_5GHZ &&
    1062                 :            :                     chan->band != NL80211_BAND_6GHZ)
    1063                 :            :                         continue;
    1064                 :            : 
    1065                 :            :                 r1 = cfg80211_get_unii(chan->center_freq);
    1066                 :            :                 r2 = cfg80211_get_unii(other_chan->center_freq);
    1067                 :            : 
    1068                 :            :                 if (r1 != -EINVAL && r1 == r2) {
    1069                 :            :                         /*
    1070                 :            :                          * At some locations channels 149-165 are considered a
    1071                 :            :                          * bundle, but at other locations, e.g., Indonesia,
    1072                 :            :                          * channels 149-161 are considered a bundle while
    1073                 :            :                          * channel 165 is left out and considered to be in a
    1074                 :            :                          * different bundle. Thus, in case that there is a
    1075                 :            :                          * station interface connected to an AP on channel 165,
    1076                 :            :                          * it is assumed that channels 149-161 are allowed for
    1077                 :            :                          * GO operations. However, having a station interface
    1078                 :            :                          * connected to an AP on channels 149-161, does not
    1079                 :            :                          * allow GO operation on channel 165.
    1080                 :            :                          */
    1081                 :            :                         if (chan->center_freq == 5825 &&
    1082                 :            :                             other_chan->center_freq != 5825)
    1083                 :            :                                 continue;
    1084                 :            :                         return true;
    1085                 :            :                 }
    1086                 :            :         }
    1087                 :            : 
    1088                 :            :         return false;
    1089                 :            : }
    1090                 :            : 
    1091                 :          0 : static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
    1092                 :            :                                      struct cfg80211_chan_def *chandef,
    1093                 :            :                                      enum nl80211_iftype iftype,
    1094                 :            :                                      bool check_no_ir)
    1095                 :            : {
    1096                 :            :         bool res;
    1097                 :            :         u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
    1098                 :            :                                IEEE80211_CHAN_RADAR;
    1099                 :            : 
    1100                 :          0 :         trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
    1101                 :            : 
    1102         [ #  # ]:          0 :         if (check_no_ir)
    1103                 :            :                 prohibited_flags |= IEEE80211_CHAN_NO_IR;
    1104                 :            : 
    1105   [ #  #  #  # ]:          0 :         if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
    1106                 :          0 :             cfg80211_chandef_dfs_available(wiphy, chandef)) {
    1107                 :            :                 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
    1108                 :            :                 prohibited_flags = IEEE80211_CHAN_DISABLED;
    1109                 :            :         }
    1110                 :            : 
    1111                 :          0 :         res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
    1112                 :            : 
    1113                 :          0 :         trace_cfg80211_return_bool(res);
    1114                 :          0 :         return res;
    1115                 :            : }
    1116                 :            : 
    1117                 :          0 : bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
    1118                 :            :                              struct cfg80211_chan_def *chandef,
    1119                 :            :                              enum nl80211_iftype iftype)
    1120                 :            : {
    1121                 :          0 :         return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
    1122                 :            : }
    1123                 :            : EXPORT_SYMBOL(cfg80211_reg_can_beacon);
    1124                 :            : 
    1125                 :          0 : bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
    1126                 :            :                                    struct cfg80211_chan_def *chandef,
    1127                 :            :                                    enum nl80211_iftype iftype)
    1128                 :            : {
    1129                 :            :         bool check_no_ir;
    1130                 :            : 
    1131   [ #  #  #  # ]:          0 :         ASSERT_RTNL();
    1132                 :            : 
    1133                 :            :         /*
    1134                 :            :          * Under certain conditions suggested by some regulatory bodies a
    1135                 :            :          * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
    1136                 :            :          * only if such relaxations are not enabled and the conditions are not
    1137                 :            :          * met.
    1138                 :            :          */
    1139                 :          0 :         check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
    1140                 :          0 :                                                    chandef->chan);
    1141                 :            : 
    1142                 :          0 :         return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
    1143                 :            : }
    1144                 :            : EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
    1145                 :            : 
    1146                 :          0 : int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
    1147                 :            :                                  struct cfg80211_chan_def *chandef)
    1148                 :            : {
    1149         [ #  # ]:          0 :         if (!rdev->ops->set_monitor_channel)
    1150                 :            :                 return -EOPNOTSUPP;
    1151         [ #  # ]:          0 :         if (!cfg80211_has_monitors_only(rdev))
    1152                 :            :                 return -EBUSY;
    1153                 :            : 
    1154                 :          0 :         return rdev_set_monitor_channel(rdev, chandef);
    1155                 :            : }
    1156                 :            : 
    1157                 :            : void
    1158                 :          0 : cfg80211_get_chan_state(struct wireless_dev *wdev,
    1159                 :            :                         struct ieee80211_channel **chan,
    1160                 :            :                         enum cfg80211_chan_mode *chanmode,
    1161                 :            :                         u8 *radar_detect)
    1162                 :            : {
    1163                 :            :         int ret;
    1164                 :            : 
    1165                 :          0 :         *chan = NULL;
    1166                 :          0 :         *chanmode = CHAN_MODE_UNDEFINED;
    1167                 :            : 
    1168                 :            :         ASSERT_WDEV_LOCK(wdev);
    1169                 :            : 
    1170   [ #  #  #  # ]:          0 :         if (wdev->netdev && !netif_running(wdev->netdev))
    1171                 :            :                 return;
    1172                 :            : 
    1173   [ #  #  #  #  :          0 :         switch (wdev->iftype) {
                #  #  # ]
    1174                 :            :         case NL80211_IFTYPE_ADHOC:
    1175         [ #  # ]:          0 :                 if (wdev->current_bss) {
    1176                 :          0 :                         *chan = wdev->current_bss->pub.channel;
    1177   [ #  #  #  # ]:          0 :                         *chanmode = (wdev->ibss_fixed &&
    1178                 :          0 :                                      !wdev->ibss_dfs_possible)
    1179                 :            :                                   ? CHAN_MODE_SHARED
    1180                 :            :                                   : CHAN_MODE_EXCLUSIVE;
    1181                 :            : 
    1182                 :            :                         /* consider worst-case - IBSS can try to return to the
    1183                 :            :                          * original user-specified channel as creator */
    1184         [ #  # ]:          0 :                         if (wdev->ibss_dfs_possible)
    1185                 :          0 :                                 *radar_detect |= BIT(wdev->chandef.width);
    1186                 :            :                         return;
    1187                 :            :                 }
    1188                 :            :                 break;
    1189                 :            :         case NL80211_IFTYPE_STATION:
    1190                 :            :         case NL80211_IFTYPE_P2P_CLIENT:
    1191         [ #  # ]:          0 :                 if (wdev->current_bss) {
    1192                 :          0 :                         *chan = wdev->current_bss->pub.channel;
    1193                 :          0 :                         *chanmode = CHAN_MODE_SHARED;
    1194                 :          0 :                         return;
    1195                 :            :                 }
    1196                 :            :                 break;
    1197                 :            :         case NL80211_IFTYPE_AP:
    1198                 :            :         case NL80211_IFTYPE_P2P_GO:
    1199         [ #  # ]:          0 :                 if (wdev->cac_started) {
    1200                 :          0 :                         *chan = wdev->chandef.chan;
    1201                 :          0 :                         *chanmode = CHAN_MODE_SHARED;
    1202                 :          0 :                         *radar_detect |= BIT(wdev->chandef.width);
    1203         [ #  # ]:          0 :                 } else if (wdev->beacon_interval) {
    1204                 :          0 :                         *chan = wdev->chandef.chan;
    1205                 :          0 :                         *chanmode = CHAN_MODE_SHARED;
    1206                 :            : 
    1207                 :          0 :                         ret = cfg80211_chandef_dfs_required(wdev->wiphy,
    1208                 :          0 :                                                             &wdev->chandef,
    1209                 :            :                                                             wdev->iftype);
    1210         [ #  # ]:          0 :                         WARN_ON(ret < 0);
    1211         [ #  # ]:          0 :                         if (ret > 0)
    1212                 :          0 :                                 *radar_detect |= BIT(wdev->chandef.width);
    1213                 :            :                 }
    1214                 :            :                 return;
    1215                 :            :         case NL80211_IFTYPE_MESH_POINT:
    1216         [ #  # ]:          0 :                 if (wdev->mesh_id_len) {
    1217                 :          0 :                         *chan = wdev->chandef.chan;
    1218                 :          0 :                         *chanmode = CHAN_MODE_SHARED;
    1219                 :            : 
    1220                 :          0 :                         ret = cfg80211_chandef_dfs_required(wdev->wiphy,
    1221                 :          0 :                                                             &wdev->chandef,
    1222                 :            :                                                             wdev->iftype);
    1223         [ #  # ]:          0 :                         WARN_ON(ret < 0);
    1224         [ #  # ]:          0 :                         if (ret > 0)
    1225                 :          0 :                                 *radar_detect |= BIT(wdev->chandef.width);
    1226                 :            :                 }
    1227                 :            :                 return;
    1228                 :            :         case NL80211_IFTYPE_OCB:
    1229         [ #  # ]:          0 :                 if (wdev->chandef.chan) {
    1230                 :          0 :                         *chan = wdev->chandef.chan;
    1231                 :          0 :                         *chanmode = CHAN_MODE_SHARED;
    1232                 :          0 :                         return;
    1233                 :            :                 }
    1234                 :            :                 break;
    1235                 :            :         case NL80211_IFTYPE_MONITOR:
    1236                 :            :         case NL80211_IFTYPE_AP_VLAN:
    1237                 :            :         case NL80211_IFTYPE_WDS:
    1238                 :            :         case NL80211_IFTYPE_P2P_DEVICE:
    1239                 :            :         case NL80211_IFTYPE_NAN:
    1240                 :            :                 /* these interface types don't really have a channel */
    1241                 :            :                 return;
    1242                 :            :         case NL80211_IFTYPE_UNSPECIFIED:
    1243                 :            :         case NUM_NL80211_IFTYPES:
    1244                 :          0 :                 WARN_ON(1);
    1245                 :            :         }
    1246                 :            : }

Generated by: LCOV version 1.14