linux/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
   9 * Copyright (C) 2018 Intel Corporation
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of version 2 of the GNU General Public License as
  13 * published by the Free Software Foundation.
  14 *
  15 * This program is distributed in the hope that it will be useful, but
  16 * WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * General Public License for more details.
  19 *
  20 * The full GNU General Public License is included in this distribution
  21 * in the file called COPYING.
  22 *
  23 * Contact Information:
  24 * Intel Linux Wireless <linuxwifi@intel.com>
  25 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  26 *
  27 * BSD LICENSE
  28 *
  29 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
  30 * Copyright (C) 2018 Intel Corporation
  31 * All rights reserved.
  32 *
  33 * Redistribution and use in source and binary forms, with or without
  34 * modification, are permitted provided that the following conditions
  35 * are met:
  36 *
  37 *  * Redistributions of source code must retain the above copyright
  38 *    notice, this list of conditions and the following disclaimer.
  39 *  * Redistributions in binary form must reproduce the above copyright
  40 *    notice, this list of conditions and the following disclaimer in
  41 *    the documentation and/or other materials provided with the
  42 *    distribution.
  43 *  * Neither the name Intel Corporation nor the names of its
  44 *    contributors may be used to endorse or promote products derived
  45 *    from this software without specific prior written permission.
  46 *
  47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  48 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  49 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  50 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  51 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  54 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  57 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  58 *
  59 *****************************************************************************/
  60#include <net/cfg80211.h>
  61#include <linux/etherdevice.h>
  62#include "mvm.h"
  63#include "constants.h"
  64
  65static int
  66iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
  67                          struct ieee80211_vif *vif,
  68                          struct cfg80211_chan_def *chandef)
  69{
  70        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  71        struct iwl_tof_responder_config_cmd cmd = {
  72                .channel_num = chandef->chan->hw_value,
  73                .cmd_valid_fields =
  74                        cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
  75                                    IWL_TOF_RESPONDER_CMD_VALID_BSSID |
  76                                    IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
  77                .sta_id = mvmvif->bcast_sta.sta_id,
  78        };
  79
  80        lockdep_assert_held(&mvm->mutex);
  81
  82        switch (chandef->width) {
  83        case NL80211_CHAN_WIDTH_20_NOHT:
  84                cmd.bandwidth = IWL_TOF_BW_20_LEGACY;
  85                break;
  86        case NL80211_CHAN_WIDTH_20:
  87                cmd.bandwidth = IWL_TOF_BW_20_HT;
  88                break;
  89        case NL80211_CHAN_WIDTH_40:
  90                cmd.bandwidth = IWL_TOF_BW_40;
  91                cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
  92                break;
  93        case NL80211_CHAN_WIDTH_80:
  94                cmd.bandwidth = IWL_TOF_BW_80;
  95                cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
  96                break;
  97        default:
  98                WARN_ON(1);
  99                return -EINVAL;
 100        }
 101
 102        memcpy(cmd.bssid, vif->addr, ETH_ALEN);
 103
 104        return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD,
 105                                                    LOCATION_GROUP, 0),
 106                                    0, sizeof(cmd), &cmd);
 107}
 108
 109static int
 110iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
 111                                  struct ieee80211_vif *vif,
 112                                  struct ieee80211_ftm_responder_params *params)
 113{
 114        struct iwl_tof_responder_dyn_config_cmd cmd = {
 115                .lci_len = cpu_to_le32(params->lci_len + 2),
 116                .civic_len = cpu_to_le32(params->civicloc_len + 2),
 117        };
 118        u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0};
 119        struct iwl_host_cmd hcmd = {
 120                .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD,
 121                                 LOCATION_GROUP, 0),
 122                .data[0] = &cmd,
 123                .len[0] = sizeof(cmd),
 124                .data[1] = &data,
 125                /* .len[1] set later */
 126                /* may not be able to DMA from stack */
 127                .dataflags[1] = IWL_HCMD_DFL_DUP,
 128        };
 129        u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4);
 130        u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4);
 131        u8 *pos = data;
 132
 133        lockdep_assert_held(&mvm->mutex);
 134
 135        if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) {
 136                IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n",
 137                        params->lci_len, params->civicloc_len);
 138                return -ENOBUFS;
 139        }
 140
 141        pos[0] = WLAN_EID_MEASURE_REPORT;
 142        pos[1] = params->lci_len;
 143        memcpy(pos + 2, params->lci, params->lci_len);
 144
 145        pos += aligned_lci_len;
 146        pos[0] = WLAN_EID_MEASURE_REPORT;
 147        pos[1] = params->civicloc_len;
 148        memcpy(pos + 2, params->civicloc, params->civicloc_len);
 149
 150        hcmd.len[1] = aligned_lci_len + aligned_civicloc_len;
 151
 152        return iwl_mvm_send_cmd(mvm, &hcmd);
 153}
 154
 155int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 156{
 157        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 158        struct ieee80211_ftm_responder_params *params;
 159        struct ieee80211_chanctx_conf ctx, *pctx;
 160        u16 *phy_ctxt_id;
 161        struct iwl_mvm_phy_ctxt *phy_ctxt;
 162        int ret;
 163
 164        params = vif->bss_conf.ftmr_params;
 165
 166        lockdep_assert_held(&mvm->mutex);
 167
 168        if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
 169                return -EINVAL;
 170
 171        if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
 172            !mvmvif->ap_ibss_active) {
 173                IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
 174                return -EIO;
 175        }
 176
 177        rcu_read_lock();
 178        pctx = rcu_dereference(vif->chanctx_conf);
 179        /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
 180         * about changes in the ctx after releasing the lock because the driver
 181         * is still protected by the mutex. */
 182        ctx = *pctx;
 183        phy_ctxt_id  = (u16 *)pctx->drv_priv;
 184        rcu_read_unlock();
 185
 186        phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
 187        ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def,
 188                                       ctx.rx_chains_static,
 189                                       ctx.rx_chains_dynamic);
 190        if (ret)
 191                return ret;
 192
 193        ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
 194        if (ret)
 195                return ret;
 196
 197        if (params)
 198                ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params);
 199
 200        return ret;
 201}
 202
 203void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
 204                                   struct ieee80211_vif *vif)
 205{
 206        if (!vif->bss_conf.ftm_responder)
 207                return;
 208
 209        iwl_mvm_ftm_start_responder(mvm, vif);
 210}
 211
 212void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
 213                                 struct iwl_rx_cmd_buffer *rxb)
 214{
 215        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 216        struct iwl_ftm_responder_stats *resp = (void *)pkt->data;
 217        struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats;
 218        u32 flags = le32_to_cpu(resp->flags);
 219
 220        if (resp->success_ftm == resp->ftm_per_burst)
 221                stats->success_num++;
 222        else if (resp->success_ftm >= 2)
 223                stats->partial_num++;
 224        else
 225                stats->failed_num++;
 226
 227        if ((flags & FTM_RESP_STAT_ASAP_REQ) &&
 228            (flags & FTM_RESP_STAT_ASAP_RESP))
 229                stats->asap_num++;
 230
 231        if (flags & FTM_RESP_STAT_NON_ASAP_RESP)
 232                stats->non_asap_num++;
 233
 234        stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC;
 235
 236        if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN)
 237                stats->unknown_triggers_num++;
 238
 239        if (flags & FTM_RESP_STAT_DUP)
 240                stats->reschedule_requests_num++;
 241
 242        if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN)
 243                stats->out_of_window_triggers_num++;
 244}
 245