chan->max_power = chan->max_reg_power;
 }
 
+static void handle_channel_adjacent_rules(struct wiphy *wiphy,
+                                         enum nl80211_reg_initiator initiator,
+                                         struct ieee80211_channel *chan,
+                                         u32 flags,
+                                         struct regulatory_request *lr,
+                                         struct wiphy *request_wiphy,
+                                         const struct ieee80211_reg_rule *rrule1,
+                                         const struct ieee80211_reg_rule *rrule2,
+                                         struct ieee80211_freq_range *comb_range)
+{
+       u32 bw_flags1 = 0;
+       u32 bw_flags2 = 0;
+       const struct ieee80211_power_rule *power_rule1 = NULL;
+       const struct ieee80211_power_rule *power_rule2 = NULL;
+       const struct ieee80211_regdomain *regd;
+
+       regd = reg_get_regdomain(wiphy);
+
+       power_rule1 = &rrule1->power_rule;
+       power_rule2 = &rrule2->power_rule;
+       bw_flags1 = reg_rule_to_chan_bw_flags(regd, rrule1, chan);
+       bw_flags2 = reg_rule_to_chan_bw_flags(regd, rrule2, chan);
+
+       if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           request_wiphy && request_wiphy == wiphy &&
+           request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
+               /* This guarantees the driver's requested regulatory domain
+                * will always be used as a base for further regulatory
+                * settings
+                */
+               chan->flags =
+                       map_regdom_flags(rrule1->flags) |
+                       map_regdom_flags(rrule2->flags) |
+                       bw_flags1 |
+                       bw_flags2;
+               chan->orig_flags = chan->flags;
+               chan->max_antenna_gain =
+                       min_t(int, MBI_TO_DBI(power_rule1->max_antenna_gain),
+                             MBI_TO_DBI(power_rule2->max_antenna_gain));
+               chan->orig_mag = chan->max_antenna_gain;
+               chan->max_reg_power =
+                       min_t(int, MBM_TO_DBM(power_rule1->max_eirp),
+                             MBM_TO_DBM(power_rule2->max_eirp));
+               chan->max_power = chan->max_reg_power;
+               chan->orig_mpwr = chan->max_reg_power;
+
+               if (chan->flags & IEEE80211_CHAN_RADAR) {
+                       chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+                       if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms)
+                               chan->dfs_cac_ms = max_t(unsigned int,
+                                                        rrule1->dfs_cac_ms,
+                                                        rrule2->dfs_cac_ms);
+               }
+
+               return;
+       }
+
+       chan->dfs_state = NL80211_DFS_USABLE;
+       chan->dfs_state_entered = jiffies;
+
+       chan->beacon_found = false;
+       chan->flags = flags | bw_flags1 | bw_flags2 |
+                     map_regdom_flags(rrule1->flags) |
+                     map_regdom_flags(rrule2->flags);
+
+       /* reg_rule_to_chan_bw_flags may forbids 10 and forbids 20 MHz
+        * (otherwise no adj. rule case), recheck therefore
+        */
+       if (cfg80211_does_bw_fit_range(comb_range,
+                                      ieee80211_channel_to_khz(chan),
+                                      MHZ_TO_KHZ(10)))
+               chan->flags &= ~IEEE80211_CHAN_NO_10MHZ;
+       if (cfg80211_does_bw_fit_range(comb_range,
+                                      ieee80211_channel_to_khz(chan),
+                                      MHZ_TO_KHZ(20)))
+               chan->flags &= ~IEEE80211_CHAN_NO_20MHZ;
+
+       chan->max_antenna_gain =
+               min_t(int, chan->orig_mag,
+                     min_t(int,
+                           MBI_TO_DBI(power_rule1->max_antenna_gain),
+                           MBI_TO_DBI(power_rule2->max_antenna_gain)));
+       chan->max_reg_power = min_t(int,
+                                   MBM_TO_DBM(power_rule1->max_eirp),
+                                   MBM_TO_DBM(power_rule2->max_eirp));
+
+       if (chan->flags & IEEE80211_CHAN_RADAR) {
+               if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms)
+                       chan->dfs_cac_ms = max_t(unsigned int,
+                                                rrule1->dfs_cac_ms,
+                                                rrule2->dfs_cac_ms);
+               else
+                       chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+       }
+
+       if (chan->orig_mpwr) {
+               /* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
+                * will always follow the passed country IE power settings.
+                */
+               if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+                   wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)
+                       chan->max_power = chan->max_reg_power;
+               else
+                       chan->max_power = min(chan->orig_mpwr,
+                                             chan->max_reg_power);
+       } else {
+               chan->max_power = chan->max_reg_power;
+       }
+}
+
 /* Note that right now we assume the desired channel bandwidth
  * is always 20 MHz for each individual channel (HT40 uses 20 MHz
  * per channel, the primary and the extension channel).
                           enum nl80211_reg_initiator initiator,
                           struct ieee80211_channel *chan)
 {
-       u32 flags = 0;
-       const struct ieee80211_reg_rule *reg_rule = NULL;
-       struct wiphy *request_wiphy = NULL;
+       const u32 orig_chan_freq = ieee80211_channel_to_khz(chan);
        struct regulatory_request *lr = get_last_request();
+       struct wiphy *request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+       const struct ieee80211_reg_rule *rrule = NULL;
+       const struct ieee80211_reg_rule *rrule1 = NULL;
+       const struct ieee80211_reg_rule *rrule2 = NULL;
+
+       u32 flags = chan->orig_flags;
+
+       rrule = freq_reg_info(wiphy, orig_chan_freq);
+       if (IS_ERR(rrule)) {
+               /* check for adjacent match, therefore get rules for
+                * chan - 20 MHz and chan + 20 MHz and test
+                * if reg rules are adjacent
+                */
+               rrule1 = freq_reg_info(wiphy,
+                                      orig_chan_freq - MHZ_TO_KHZ(20));
+               rrule2 = freq_reg_info(wiphy,
+                                      orig_chan_freq + MHZ_TO_KHZ(20));
+               if (!IS_ERR(rrule1) && !IS_ERR(rrule2)) {
+                       struct ieee80211_freq_range comb_range;
+
+                       if (rrule1->freq_range.end_freq_khz !=
+                           rrule2->freq_range.start_freq_khz)
+                               goto disable_chan;
+
+                       comb_range.start_freq_khz =
+                               rrule1->freq_range.start_freq_khz;
+                       comb_range.end_freq_khz =
+                               rrule2->freq_range.end_freq_khz;
+                       comb_range.max_bandwidth_khz =
+                               min_t(u32,
+                                     rrule1->freq_range.max_bandwidth_khz,
+                                     rrule2->freq_range.max_bandwidth_khz);
+
+                       if (!cfg80211_does_bw_fit_range(&comb_range,
+                                                       orig_chan_freq,
+                                                       MHZ_TO_KHZ(20)))
+                               goto disable_chan;
+
+                       handle_channel_adjacent_rules(wiphy, initiator, chan,
+                                                     flags, lr, request_wiphy,
+                                                     rrule1, rrule2,
+                                                     &comb_range);
+                       return;
+               }
 
-       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
-
-       flags = chan->orig_flags;
-
-       reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
-       if (IS_ERR(reg_rule)) {
+disable_chan:
                /* We will disable all channels that do not match our
                 * received regulatory rule unless the hint is coming
                 * from a Country IE and the Country IE had no information
                 * while 5 GHz is still supported.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-                   PTR_ERR(reg_rule) == -ERANGE)
+                   PTR_ERR(rrule) == -ERANGE)
                        return;
 
                if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
        }
 
        handle_channel_single_rule(wiphy, initiator, chan, flags, lr,
-                                  request_wiphy, reg_rule);
+                                  request_wiphy, rrule);
 }
 
 static void handle_band(struct wiphy *wiphy,