Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: 802.11h
0004  *
0005  * Copyright 2011-2020 NXP
0006  */
0007 
0008 #include "main.h"
0009 #include "fw.h"
0010 
0011 
0012 void mwifiex_init_11h_params(struct mwifiex_private *priv)
0013 {
0014     priv->state_11h.is_11h_enabled = true;
0015     priv->state_11h.is_11h_active = false;
0016 }
0017 
0018 inline int mwifiex_is_11h_active(struct mwifiex_private *priv)
0019 {
0020     return priv->state_11h.is_11h_active;
0021 }
0022 /* This function appends 11h info to a buffer while joining an
0023  * infrastructure BSS
0024  */
0025 static void
0026 mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
0027                    struct mwifiex_bssdescriptor *bss_desc)
0028 {
0029     struct mwifiex_ie_types_header *ie_header;
0030     struct mwifiex_ie_types_pwr_capability *cap;
0031     struct mwifiex_ie_types_local_pwr_constraint *constraint;
0032     struct ieee80211_supported_band *sband;
0033     u8 radio_type;
0034     int i;
0035 
0036     if (!buffer || !(*buffer))
0037         return;
0038 
0039     radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
0040     sband = priv->wdev.wiphy->bands[radio_type];
0041 
0042     cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
0043     cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
0044     cap->header.len = cpu_to_le16(2);
0045     cap->min_pwr = 0;
0046     cap->max_pwr = 0;
0047     *buffer += sizeof(*cap);
0048 
0049     constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer;
0050     constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
0051     constraint->header.len = cpu_to_le16(2);
0052     constraint->chan = bss_desc->channel;
0053     constraint->constraint = bss_desc->local_constraint;
0054     *buffer += sizeof(*constraint);
0055 
0056     ie_header = (struct mwifiex_ie_types_header *)*buffer;
0057     ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
0058     ie_header->len  = cpu_to_le16(2 * sband->n_channels + 2);
0059     *buffer += sizeof(*ie_header);
0060     *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
0061     *(*buffer)++ = 2 * sband->n_channels;
0062     for (i = 0; i < sband->n_channels; i++) {
0063         *(*buffer)++ = ieee80211_frequency_to_channel(
0064                     sband->channels[i].center_freq);
0065         *(*buffer)++ = 1; /* one channel in the subband */
0066     }
0067 }
0068 
0069 /* Enable or disable the 11h extensions in the firmware */
0070 int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
0071 {
0072     u32 enable = flag;
0073 
0074     /* enable master mode radar detection on AP interface */
0075     if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable)
0076         enable |= MWIFIEX_MASTER_RADAR_DET_MASK;
0077 
0078     return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
0079                 HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true);
0080 }
0081 
0082 /* This functions processes TLV buffer for a pending BSS Join command.
0083  *
0084  * Activate 11h functionality in the firmware if the spectrum management
0085  * capability bit is found in the network we are joining. Also, necessary
0086  * TLVs are set based on requested network's 11h capability.
0087  */
0088 void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
0089                   struct mwifiex_bssdescriptor *bss_desc)
0090 {
0091     if (bss_desc->sensed_11h) {
0092         /* Activate 11h functions in firmware, turns on capability
0093          * bit
0094          */
0095         mwifiex_11h_activate(priv, true);
0096         priv->state_11h.is_11h_active = true;
0097         bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
0098         mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
0099     } else {
0100         /* Deactivate 11h functions in the firmware */
0101         mwifiex_11h_activate(priv, false);
0102         priv->state_11h.is_11h_active = false;
0103         bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
0104     }
0105 }
0106 
0107 /* This is DFS CAC work queue function.
0108  * This delayed work emits CAC finished event for cfg80211 if
0109  * CAC was started earlier.
0110  */
0111 void mwifiex_dfs_cac_work_queue(struct work_struct *work)
0112 {
0113     struct cfg80211_chan_def chandef;
0114     struct delayed_work *delayed_work = to_delayed_work(work);
0115     struct mwifiex_private *priv =
0116             container_of(delayed_work, struct mwifiex_private,
0117                      dfs_cac_work);
0118 
0119     chandef = priv->dfs_chandef;
0120     if (priv->wdev.cac_started) {
0121         mwifiex_dbg(priv->adapter, MSG,
0122                 "CAC timer finished; No radar detected\n");
0123         cfg80211_cac_event(priv->netdev, &chandef,
0124                    NL80211_RADAR_CAC_FINISHED,
0125                    GFP_KERNEL);
0126     }
0127 }
0128 
0129 /* This function prepares channel report request command to FW for
0130  * starting radar detection.
0131  */
0132 int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
0133                       struct host_cmd_ds_command *cmd,
0134                       void *data_buf)
0135 {
0136     struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
0137     struct mwifiex_radar_params *radar_params = (void *)data_buf;
0138 
0139     cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST);
0140     cmd->size = cpu_to_le16(S_DS_GEN);
0141     le16_unaligned_add_cpu(&cmd->size,
0142                    sizeof(struct host_cmd_ds_chan_rpt_req));
0143 
0144     cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ);
0145     cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
0146     cr_req->chan_desc.chan_width = radar_params->chandef->width;
0147     cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
0148 
0149     if (radar_params->cac_time_ms)
0150         mwifiex_dbg(priv->adapter, MSG,
0151                 "11h: issuing DFS Radar check for channel=%d\n",
0152                 radar_params->chandef->chan->hw_value);
0153     else
0154         mwifiex_dbg(priv->adapter, MSG, "cancelling CAC\n");
0155 
0156     return 0;
0157 }
0158 
0159 int mwifiex_stop_radar_detection(struct mwifiex_private *priv,
0160                  struct cfg80211_chan_def *chandef)
0161 {
0162     struct mwifiex_radar_params radar_params;
0163 
0164     memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
0165     radar_params.chandef = chandef;
0166     radar_params.cac_time_ms = 0;
0167 
0168     return mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
0169                 HostCmd_ACT_GEN_SET, 0, &radar_params, true);
0170 }
0171 
0172 /* This function is to abort ongoing CAC upon stopping AP operations
0173  * or during unload.
0174  */
0175 void mwifiex_abort_cac(struct mwifiex_private *priv)
0176 {
0177     if (priv->wdev.cac_started) {
0178         if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
0179             mwifiex_dbg(priv->adapter, ERROR,
0180                     "failed to stop CAC in FW\n");
0181         mwifiex_dbg(priv->adapter, MSG,
0182                 "Aborting delayed work for CAC.\n");
0183         cancel_delayed_work_sync(&priv->dfs_cac_work);
0184         cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
0185                    NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
0186     }
0187 }
0188 
0189 /* This function handles channel report event from FW during CAC period.
0190  * If radar is detected during CAC, driver indicates the same to cfg80211
0191  * and also cancels ongoing delayed work.
0192  */
0193 int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
0194                      struct sk_buff *skb)
0195 {
0196     struct host_cmd_ds_chan_rpt_event *rpt_event;
0197     struct mwifiex_ie_types_chan_rpt_data *rpt;
0198     u8 *evt_buf;
0199     u16 event_len, tlv_len;
0200 
0201     rpt_event = (void *)(skb->data + sizeof(u32));
0202     event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+
0203                 sizeof(u32));
0204 
0205     if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) {
0206         mwifiex_dbg(priv->adapter, ERROR,
0207                 "Error in channel report event\n");
0208         return -1;
0209     }
0210 
0211     evt_buf = (void *)&rpt_event->tlvbuf;
0212 
0213     while (event_len >= sizeof(struct mwifiex_ie_types_header)) {
0214         rpt = (void *)&rpt_event->tlvbuf;
0215         tlv_len = le16_to_cpu(rpt->header.len);
0216 
0217         switch (le16_to_cpu(rpt->header.type)) {
0218         case TLV_TYPE_CHANRPT_11H_BASIC:
0219             if (rpt->map.radar) {
0220                 mwifiex_dbg(priv->adapter, MSG,
0221                         "RADAR Detected on channel %d!\n",
0222                         priv->dfs_chandef.chan->hw_value);
0223                 cancel_delayed_work_sync(&priv->dfs_cac_work);
0224                 cfg80211_cac_event(priv->netdev,
0225                            &priv->dfs_chandef,
0226                            NL80211_RADAR_DETECTED,
0227                            GFP_KERNEL);
0228             }
0229             break;
0230         default:
0231             break;
0232         }
0233 
0234         evt_buf += (tlv_len + sizeof(rpt->header));
0235         event_len -= (tlv_len + sizeof(rpt->header));
0236     }
0237 
0238     return 0;
0239 }
0240 
0241 /* Handler for radar detected event from FW.*/
0242 int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
0243                       struct sk_buff *skb)
0244 {
0245     struct mwifiex_radar_det_event *rdr_event;
0246 
0247     rdr_event = (void *)(skb->data + sizeof(u32));
0248 
0249     mwifiex_dbg(priv->adapter, MSG,
0250             "radar detected; indicating kernel\n");
0251     if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
0252         mwifiex_dbg(priv->adapter, ERROR,
0253                 "Failed to stop CAC in FW\n");
0254     cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
0255                  GFP_KERNEL);
0256     mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n",
0257             rdr_event->reg_domain);
0258     mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n",
0259             rdr_event->det_type);
0260 
0261     return 0;
0262 }
0263 
0264 /* This is work queue function for channel switch handling.
0265  * This function takes care of updating new channel definitin to
0266  * bss config structure, restart AP and indicate channel switch success
0267  * to cfg80211.
0268  */
0269 void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
0270 {
0271     struct mwifiex_uap_bss_param *bss_cfg;
0272     struct delayed_work *delayed_work = to_delayed_work(work);
0273     struct mwifiex_private *priv =
0274             container_of(delayed_work, struct mwifiex_private,
0275                      dfs_chan_sw_work);
0276 
0277     bss_cfg = &priv->bss_cfg;
0278     if (!bss_cfg->beacon_period) {
0279         mwifiex_dbg(priv->adapter, ERROR,
0280                 "channel switch: AP already stopped\n");
0281         return;
0282     }
0283 
0284     mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef);
0285 
0286     if (mwifiex_config_start_uap(priv, bss_cfg)) {
0287         mwifiex_dbg(priv->adapter, ERROR,
0288                 "Failed to start AP after channel switch\n");
0289         return;
0290     }
0291 
0292     mwifiex_dbg(priv->adapter, MSG,
0293             "indicating channel switch completion to kernel\n");
0294     mutex_lock(&priv->wdev.mtx);
0295     cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0);
0296     mutex_unlock(&priv->wdev.mtx);
0297 }