Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2015-2017 Intel Deutschland GmbH
0004  * Copyright (C) 2018-2022 Intel Corporation
0005  */
0006 #include <net/cfg80211.h>
0007 #include <linux/etherdevice.h>
0008 #include "mvm.h"
0009 #include "constants.h"
0010 
0011 struct iwl_mvm_pasn_sta {
0012     struct list_head list;
0013     struct iwl_mvm_int_sta int_sta;
0014     u8 addr[ETH_ALEN];
0015 };
0016 
0017 struct iwl_mvm_pasn_hltk_data {
0018     u8 *addr;
0019     u8 cipher;
0020     u8 *hltk;
0021 };
0022 
0023 static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef,
0024                        u8 *bw, u8 *ctrl_ch_position)
0025 {
0026     switch (chandef->width) {
0027     case NL80211_CHAN_WIDTH_20_NOHT:
0028         *bw = IWL_TOF_BW_20_LEGACY;
0029         break;
0030     case NL80211_CHAN_WIDTH_20:
0031         *bw = IWL_TOF_BW_20_HT;
0032         break;
0033     case NL80211_CHAN_WIDTH_40:
0034         *bw = IWL_TOF_BW_40;
0035         *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
0036         break;
0037     case NL80211_CHAN_WIDTH_80:
0038         *bw = IWL_TOF_BW_80;
0039         *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
0040         break;
0041     default:
0042         return -ENOTSUPP;
0043     }
0044 
0045     return 0;
0046 }
0047 
0048 static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef,
0049                        u8 *format_bw, u8 *ctrl_ch_position,
0050                        u8 cmd_ver)
0051 {
0052     switch (chandef->width) {
0053     case NL80211_CHAN_WIDTH_20_NOHT:
0054         *format_bw = IWL_LOCATION_FRAME_FORMAT_LEGACY;
0055         *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
0056         break;
0057     case NL80211_CHAN_WIDTH_20:
0058         *format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
0059         *format_bw |= IWL_LOCATION_BW_20MHZ << LOCATION_BW_POS;
0060         break;
0061     case NL80211_CHAN_WIDTH_40:
0062         *format_bw = IWL_LOCATION_FRAME_FORMAT_HT;
0063         *format_bw |= IWL_LOCATION_BW_40MHZ << LOCATION_BW_POS;
0064         *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
0065         break;
0066     case NL80211_CHAN_WIDTH_80:
0067         *format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
0068         *format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
0069         *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
0070         break;
0071     case NL80211_CHAN_WIDTH_160:
0072         if (cmd_ver >= 9) {
0073             *format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
0074             *format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
0075             *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
0076             break;
0077         }
0078         fallthrough;
0079     default:
0080         return -ENOTSUPP;
0081     }
0082 
0083     return 0;
0084 }
0085 
0086 static void
0087 iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm,
0088                   struct iwl_tof_responder_config_cmd_v9 *cmd)
0089 {
0090     /* Up to 2 R2I STS are allowed on the responder */
0091     u32 r2i_max_sts = IWL_MVM_FTM_R2I_MAX_STS < 2 ?
0092         IWL_MVM_FTM_R2I_MAX_STS : 1;
0093 
0094     cmd->r2i_ndp_params = IWL_MVM_FTM_R2I_MAX_REP |
0095         (r2i_max_sts << IWL_RESPONDER_STS_POS) |
0096         (IWL_MVM_FTM_R2I_MAX_TOTAL_LTF << IWL_RESPONDER_TOTAL_LTF_POS);
0097     cmd->i2r_ndp_params = IWL_MVM_FTM_I2R_MAX_REP |
0098         (IWL_MVM_FTM_I2R_MAX_STS << IWL_RESPONDER_STS_POS) |
0099         (IWL_MVM_FTM_I2R_MAX_TOTAL_LTF << IWL_RESPONDER_TOTAL_LTF_POS);
0100     cmd->cmd_valid_fields |=
0101         cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_NDP_PARAMS);
0102 }
0103 
0104 static int
0105 iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
0106               struct ieee80211_vif *vif,
0107               struct cfg80211_chan_def *chandef)
0108 {
0109     u32 cmd_id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD);
0110     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0111     /*
0112      * The command structure is the same for versions 6, 7 and 8 (only the
0113      * field interpretation is different), so the same struct can be use
0114      * for all cases.
0115      */
0116     struct iwl_tof_responder_config_cmd_v9 cmd = {
0117         .channel_num = chandef->chan->hw_value,
0118         .cmd_valid_fields =
0119             cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
0120                     IWL_TOF_RESPONDER_CMD_VALID_BSSID |
0121                     IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
0122         .sta_id = mvmvif->bcast_sta.sta_id,
0123     };
0124     u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6);
0125     int err;
0126     int cmd_size;
0127 
0128     lockdep_assert_held(&mvm->mutex);
0129 
0130     /* Use a default of bss_color=1 for now */
0131     if (cmd_ver == 9) {
0132         cmd.cmd_valid_fields |=
0133             cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR |
0134                     IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR);
0135         cmd.bss_color = 1;
0136         cmd.min_time_between_msr =
0137             cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR);
0138         cmd.max_time_between_msr =
0139             cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR);
0140         cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v9);
0141     } else {
0142         /* All versions up to version 8 have the same size */
0143         cmd_size = sizeof(struct iwl_tof_responder_config_cmd_v8);
0144     }
0145 
0146     if (cmd_ver >= 8)
0147         iwl_mvm_ftm_responder_set_ndp(mvm, &cmd);
0148 
0149     if (cmd_ver >= 7)
0150         err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw,
0151                               &cmd.ctrl_ch_position,
0152                               cmd_ver);
0153     else
0154         err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw,
0155                               &cmd.ctrl_ch_position);
0156 
0157     if (err) {
0158         IWL_ERR(mvm, "Failed to set responder bandwidth\n");
0159         return err;
0160     }
0161 
0162     memcpy(cmd.bssid, vif->addr, ETH_ALEN);
0163 
0164     return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd);
0165 }
0166 
0167 static int
0168 iwl_mvm_ftm_responder_dyn_cfg_v2(struct iwl_mvm *mvm,
0169                  struct ieee80211_vif *vif,
0170                  struct ieee80211_ftm_responder_params *params)
0171 {
0172     struct iwl_tof_responder_dyn_config_cmd_v2 cmd = {
0173         .lci_len = cpu_to_le32(params->lci_len + 2),
0174         .civic_len = cpu_to_le32(params->civicloc_len + 2),
0175     };
0176     u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0};
0177     struct iwl_host_cmd hcmd = {
0178         .id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD),
0179         .data[0] = &cmd,
0180         .len[0] = sizeof(cmd),
0181         .data[1] = &data,
0182         /* .len[1] set later */
0183         /* may not be able to DMA from stack */
0184         .dataflags[1] = IWL_HCMD_DFL_DUP,
0185     };
0186     u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4);
0187     u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4);
0188     u8 *pos = data;
0189 
0190     lockdep_assert_held(&mvm->mutex);
0191 
0192     if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) {
0193         IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n",
0194             params->lci_len, params->civicloc_len);
0195         return -ENOBUFS;
0196     }
0197 
0198     pos[0] = WLAN_EID_MEASURE_REPORT;
0199     pos[1] = params->lci_len;
0200     memcpy(pos + 2, params->lci, params->lci_len);
0201 
0202     pos += aligned_lci_len;
0203     pos[0] = WLAN_EID_MEASURE_REPORT;
0204     pos[1] = params->civicloc_len;
0205     memcpy(pos + 2, params->civicloc, params->civicloc_len);
0206 
0207     hcmd.len[1] = aligned_lci_len + aligned_civicloc_len;
0208 
0209     return iwl_mvm_send_cmd(mvm, &hcmd);
0210 }
0211 
0212 static int
0213 iwl_mvm_ftm_responder_dyn_cfg_v3(struct iwl_mvm *mvm,
0214                  struct ieee80211_vif *vif,
0215                  struct ieee80211_ftm_responder_params *params,
0216                  struct iwl_mvm_pasn_hltk_data *hltk_data)
0217 {
0218     struct iwl_tof_responder_dyn_config_cmd cmd;
0219     struct iwl_host_cmd hcmd = {
0220         .id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD),
0221         .data[0] = &cmd,
0222         .len[0] = sizeof(cmd),
0223         /* may not be able to DMA from stack */
0224         .dataflags[0] = IWL_HCMD_DFL_DUP,
0225     };
0226 
0227     lockdep_assert_held(&mvm->mutex);
0228 
0229     cmd.valid_flags = 0;
0230 
0231     if (params) {
0232         if (params->lci_len + 2 > sizeof(cmd.lci_buf) ||
0233             params->civicloc_len + 2 > sizeof(cmd.civic_buf)) {
0234             IWL_ERR(mvm,
0235                 "LCI/civic data too big (lci=%zd, civic=%zd)\n",
0236                 params->lci_len, params->civicloc_len);
0237             return -ENOBUFS;
0238         }
0239 
0240         cmd.lci_buf[0] = WLAN_EID_MEASURE_REPORT;
0241         cmd.lci_buf[1] = params->lci_len;
0242         memcpy(cmd.lci_buf + 2, params->lci, params->lci_len);
0243         cmd.lci_len = params->lci_len + 2;
0244 
0245         cmd.civic_buf[0] = WLAN_EID_MEASURE_REPORT;
0246         cmd.civic_buf[1] = params->civicloc_len;
0247         memcpy(cmd.civic_buf + 2, params->civicloc,
0248                params->civicloc_len);
0249         cmd.civic_len = params->civicloc_len + 2;
0250 
0251         cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_LCI |
0252             IWL_RESPONDER_DYN_CFG_VALID_CIVIC;
0253     }
0254 
0255     if (hltk_data) {
0256         if (hltk_data->cipher > IWL_LOCATION_CIPHER_GCMP_256) {
0257             IWL_ERR(mvm, "invalid cipher: %u\n",
0258                 hltk_data->cipher);
0259             return -EINVAL;
0260         }
0261 
0262         cmd.cipher = hltk_data->cipher;
0263         memcpy(cmd.addr, hltk_data->addr, sizeof(cmd.addr));
0264         memcpy(cmd.hltk_buf, hltk_data->hltk, sizeof(cmd.hltk_buf));
0265         cmd.valid_flags |= IWL_RESPONDER_DYN_CFG_VALID_PASN_STA;
0266     }
0267 
0268     return iwl_mvm_send_cmd(mvm, &hcmd);
0269 }
0270 
0271 static int
0272 iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
0273                   struct ieee80211_vif *vif,
0274                   struct ieee80211_ftm_responder_params *params)
0275 {
0276     int ret;
0277     u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
0278                        WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD),
0279                        2);
0280 
0281     switch (cmd_ver) {
0282     case 2:
0283         ret = iwl_mvm_ftm_responder_dyn_cfg_v2(mvm, vif,
0284                                params);
0285         break;
0286     case 3:
0287         ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif,
0288                                params, NULL);
0289         break;
0290     default:
0291         IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n",
0292             cmd_ver);
0293         ret = -ENOTSUPP;
0294     }
0295 
0296     return ret;
0297 }
0298 
0299 static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm,
0300                       struct ieee80211_vif *vif,
0301                       struct iwl_mvm_pasn_sta *sta)
0302 {
0303     list_del(&sta->list);
0304     iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id);
0305     iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta);
0306     kfree(sta);
0307 }
0308 
0309 int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
0310                       struct ieee80211_vif *vif,
0311                       u8 *addr, u32 cipher, u8 *tk, u32 tk_len,
0312                       u8 *hltk, u32 hltk_len)
0313 {
0314     int ret;
0315     struct iwl_mvm_pasn_sta *sta = NULL;
0316     struct iwl_mvm_pasn_hltk_data hltk_data = {
0317         .addr = addr,
0318         .hltk = hltk,
0319     };
0320     u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
0321                        WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_DYN_CONFIG_CMD),
0322                        2);
0323 
0324     lockdep_assert_held(&mvm->mutex);
0325 
0326     if (cmd_ver < 3) {
0327         IWL_ERR(mvm, "Adding PASN station not supported by FW\n");
0328         return -ENOTSUPP;
0329     }
0330 
0331     hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher);
0332     if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) {
0333         IWL_ERR(mvm, "invalid cipher: %u\n", cipher);
0334         return -EINVAL;
0335     }
0336 
0337     if (tk && tk_len) {
0338         sta = kzalloc(sizeof(*sta), GFP_KERNEL);
0339         if (!sta)
0340             return -ENOBUFS;
0341 
0342         ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr,
0343                        cipher, tk, tk_len);
0344         if (ret) {
0345             kfree(sta);
0346             return ret;
0347         }
0348 
0349         memcpy(sta->addr, addr, ETH_ALEN);
0350         list_add_tail(&sta->list, &mvm->resp_pasn_list);
0351     }
0352 
0353     ret = iwl_mvm_ftm_responder_dyn_cfg_v3(mvm, vif, NULL, &hltk_data);
0354     if (ret && sta)
0355         iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
0356 
0357     return ret;
0358 }
0359 
0360 int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
0361                      struct ieee80211_vif *vif, u8 *addr)
0362 {
0363     struct iwl_mvm_pasn_sta *sta, *prev;
0364 
0365     lockdep_assert_held(&mvm->mutex);
0366 
0367     list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) {
0368         if (!memcmp(sta->addr, addr, ETH_ALEN)) {
0369             iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
0370             return 0;
0371         }
0372     }
0373 
0374     IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr);
0375     return -EINVAL;
0376 }
0377 
0378 int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0379 {
0380     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0381     struct ieee80211_ftm_responder_params *params;
0382     struct ieee80211_chanctx_conf ctx, *pctx;
0383     u16 *phy_ctxt_id;
0384     struct iwl_mvm_phy_ctxt *phy_ctxt;
0385     int ret;
0386 
0387     params = vif->bss_conf.ftmr_params;
0388 
0389     lockdep_assert_held(&mvm->mutex);
0390 
0391     if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
0392         return -EINVAL;
0393 
0394     if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
0395         !mvmvif->ap_ibss_active) {
0396         IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
0397         return -EIO;
0398     }
0399 
0400     rcu_read_lock();
0401     pctx = rcu_dereference(vif->bss_conf.chanctx_conf);
0402     /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
0403      * about changes in the ctx after releasing the lock because the driver
0404      * is still protected by the mutex. */
0405     ctx = *pctx;
0406     phy_ctxt_id  = (u16 *)pctx->drv_priv;
0407     rcu_read_unlock();
0408 
0409     phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
0410     ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def,
0411                        ctx.rx_chains_static,
0412                        ctx.rx_chains_dynamic);
0413     if (ret)
0414         return ret;
0415 
0416     ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
0417     if (ret)
0418         return ret;
0419 
0420     if (params)
0421         ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params);
0422 
0423     return ret;
0424 }
0425 
0426 void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,
0427                  struct ieee80211_vif *vif)
0428 {
0429     struct iwl_mvm_pasn_sta *sta, *prev;
0430 
0431     lockdep_assert_held(&mvm->mutex);
0432 
0433     list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list)
0434         iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
0435 }
0436 
0437 void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
0438                    struct ieee80211_vif *vif)
0439 {
0440     if (!vif->bss_conf.ftm_responder)
0441         return;
0442 
0443     iwl_mvm_ftm_responder_clear(mvm, vif);
0444     iwl_mvm_ftm_start_responder(mvm, vif);
0445 }
0446 
0447 void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
0448                  struct iwl_rx_cmd_buffer *rxb)
0449 {
0450     struct iwl_rx_packet *pkt = rxb_addr(rxb);
0451     struct iwl_ftm_responder_stats *resp = (void *)pkt->data;
0452     struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats;
0453     u32 flags = le32_to_cpu(resp->flags);
0454 
0455     if (resp->success_ftm == resp->ftm_per_burst)
0456         stats->success_num++;
0457     else if (resp->success_ftm >= 2)
0458         stats->partial_num++;
0459     else
0460         stats->failed_num++;
0461 
0462     if ((flags & FTM_RESP_STAT_ASAP_REQ) &&
0463         (flags & FTM_RESP_STAT_ASAP_RESP))
0464         stats->asap_num++;
0465 
0466     if (flags & FTM_RESP_STAT_NON_ASAP_RESP)
0467         stats->non_asap_num++;
0468 
0469     stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC;
0470 
0471     if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN)
0472         stats->unknown_triggers_num++;
0473 
0474     if (flags & FTM_RESP_STAT_DUP)
0475         stats->reschedule_requests_num++;
0476 
0477     if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN)
0478         stats->out_of_window_triggers_num++;
0479 }