root/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iwl_mvm_set_wowlan_qos_seq
  2. iwl_mvm_send_proto_offload

   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) 2012 - 2014 Intel Corporation. All rights reserved.
   9  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  10  * Copyright(c) 2015 Intel Deutschland GmbH
  11  *
  12  * This program is free software; you can redistribute it and/or modify
  13  * it under the terms of version 2 of the GNU General Public License as
  14  * published by the Free Software Foundation.
  15  *
  16  * This program is distributed in the hope that it will be useful, but
  17  * WITHOUT ANY WARRANTY; without even the implied warranty of
  18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19  * General Public License for more details.
  20  *
  21  * The full GNU General Public License is included in this distribution
  22  * in the file called COPYING.
  23  *
  24  * Contact Information:
  25  *  Intel Linux Wireless <linuxwifi@intel.com>
  26  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27  *
  28  * BSD LICENSE
  29  *
  30  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  31  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  32  * Copyright(c) 2015 Intel Deutschland GmbH
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  *
  39  *  * Redistributions of source code must retain the above copyright
  40  *    notice, this list of conditions and the following disclaimer.
  41  *  * Redistributions in binary form must reproduce the above copyright
  42  *    notice, this list of conditions and the following disclaimer in
  43  *    the documentation and/or other materials provided with the
  44  *    distribution.
  45  *  * Neither the name Intel Corporation nor the names of its
  46  *    contributors may be used to endorse or promote products derived
  47  *    from this software without specific prior written permission.
  48  *
  49  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  50  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  51  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  52  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  53  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  54  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  55  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  59  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60  *
  61  *****************************************************************************/
  62 #include <net/ipv6.h>
  63 #include <net/addrconf.h>
  64 #include <linux/bitops.h>
  65 #include "mvm.h"
  66 
  67 void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
  68                                 struct iwl_wowlan_config_cmd *cmd)
  69 {
  70         int i;
  71 
  72         /*
  73          * For QoS counters, we store the one to use next, so subtract 0x10
  74          * since the uCode will add 0x10 *before* using the value while we
  75          * increment after using the value (i.e. store the next value to use).
  76          */
  77         for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
  78                 u16 seq = mvm_ap_sta->tid_data[i].seq_number;
  79                 seq -= 0x10;
  80                 cmd->qos_seq[i] = cpu_to_le16(seq);
  81         }
  82 }
  83 
  84 int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
  85                                struct ieee80211_vif *vif,
  86                                bool disable_offloading,
  87                                bool offload_ns,
  88                                u32 cmd_flags)
  89 {
  90         union {
  91                 struct iwl_proto_offload_cmd_v1 v1;
  92                 struct iwl_proto_offload_cmd_v2 v2;
  93                 struct iwl_proto_offload_cmd_v3_small v3s;
  94                 struct iwl_proto_offload_cmd_v3_large v3l;
  95         } cmd = {};
  96         struct iwl_host_cmd hcmd = {
  97                 .id = PROT_OFFLOAD_CONFIG_CMD,
  98                 .flags = cmd_flags,
  99                 .data[0] = &cmd,
 100                 .dataflags[0] = IWL_HCMD_DFL_DUP,
 101         };
 102         struct iwl_proto_offload_cmd_common *common;
 103         u32 enabled = 0, size;
 104         u32 capa_flags = mvm->fw->ucode_capa.flags;
 105 #if IS_ENABLED(CONFIG_IPV6)
 106         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 107         int i;
 108         /*
 109          * Skip tentative address when ns offload is enabled to avoid
 110          * violating RFC4862.
 111          * Keep tentative address when ns offload is disabled so the NS packets
 112          * will not be filtered out and will wake up the host.
 113          */
 114         bool skip_tentative = offload_ns;
 115 
 116         if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
 117             capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
 118                 struct iwl_ns_config *nsc;
 119                 struct iwl_targ_addr *addrs;
 120                 int n_nsc, n_addrs;
 121                 int c;
 122                 int num_skipped = 0;
 123 
 124                 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
 125                         nsc = cmd.v3s.ns_config;
 126                         n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
 127                         addrs = cmd.v3s.targ_addrs;
 128                         n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
 129                 } else {
 130                         nsc = cmd.v3l.ns_config;
 131                         n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
 132                         addrs = cmd.v3l.targ_addrs;
 133                         n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
 134                 }
 135 
 136                 /*
 137                  * For each address we have (and that will fit) fill a target
 138                  * address struct and combine for NS offload structs with the
 139                  * solicited node addresses.
 140                  */
 141                 for (i = 0, c = 0;
 142                      i < mvmvif->num_target_ipv6_addrs &&
 143                      i < n_addrs && c < n_nsc; i++) {
 144                         struct in6_addr solicited_addr;
 145                         int j;
 146 
 147                         if (skip_tentative &&
 148                             test_bit(i, mvmvif->tentative_addrs)) {
 149                                 num_skipped++;
 150                                 continue;
 151                         }
 152 
 153                         addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
 154                                                   &solicited_addr);
 155                         for (j = 0; j < c; j++)
 156                                 if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
 157                                                   &solicited_addr) == 0)
 158                                         break;
 159                         if (j == c)
 160                                 c++;
 161                         addrs[i].addr = mvmvif->target_ipv6_addrs[i];
 162                         addrs[i].config_num = cpu_to_le32(j);
 163                         nsc[j].dest_ipv6_addr = solicited_addr;
 164                         memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
 165                 }
 166 
 167                 if (mvmvif->num_target_ipv6_addrs - num_skipped)
 168                         enabled |= IWL_D3_PROTO_IPV6_VALID;
 169 
 170                 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
 171                         cmd.v3s.num_valid_ipv6_addrs =
 172                                 cpu_to_le32(i - num_skipped);
 173                 else
 174                         cmd.v3l.num_valid_ipv6_addrs =
 175                                 cpu_to_le32(i - num_skipped);
 176         } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
 177                 bool found = false;
 178 
 179                 BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
 180                              sizeof(mvmvif->target_ipv6_addrs[0]));
 181 
 182                 for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
 183                                     IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) {
 184                         if (skip_tentative &&
 185                             test_bit(i, mvmvif->tentative_addrs))
 186                                 continue;
 187 
 188                         memcpy(cmd.v2.target_ipv6_addr[i],
 189                                &mvmvif->target_ipv6_addrs[i],
 190                                sizeof(cmd.v2.target_ipv6_addr[i]));
 191 
 192                         found = true;
 193                 }
 194                 if (found) {
 195                         enabled |= IWL_D3_PROTO_IPV6_VALID;
 196                         memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
 197                 }
 198         } else {
 199                 bool found = false;
 200                 BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
 201                              sizeof(mvmvif->target_ipv6_addrs[0]));
 202 
 203                 for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
 204                                     IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) {
 205                         if (skip_tentative &&
 206                             test_bit(i, mvmvif->tentative_addrs))
 207                                 continue;
 208 
 209                         memcpy(cmd.v1.target_ipv6_addr[i],
 210                                &mvmvif->target_ipv6_addrs[i],
 211                                sizeof(cmd.v1.target_ipv6_addr[i]));
 212 
 213                         found = true;
 214                 }
 215 
 216                 if (found) {
 217                         enabled |= IWL_D3_PROTO_IPV6_VALID;
 218                         memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
 219                 }
 220         }
 221 
 222         if (offload_ns && (enabled & IWL_D3_PROTO_IPV6_VALID))
 223                 enabled |= IWL_D3_PROTO_OFFLOAD_NS;
 224 #endif
 225         if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
 226                 common = &cmd.v3s.common;
 227                 size = sizeof(cmd.v3s);
 228         } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
 229                 common = &cmd.v3l.common;
 230                 size = sizeof(cmd.v3l);
 231         } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
 232                 common = &cmd.v2.common;
 233                 size = sizeof(cmd.v2);
 234         } else {
 235                 common = &cmd.v1.common;
 236                 size = sizeof(cmd.v1);
 237         }
 238 
 239         if (vif->bss_conf.arp_addr_cnt) {
 240                 enabled |= IWL_D3_PROTO_OFFLOAD_ARP | IWL_D3_PROTO_IPV4_VALID;
 241                 common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
 242                 memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
 243         }
 244 
 245         if (!disable_offloading)
 246                 common->enabled = cpu_to_le32(enabled);
 247 
 248         hcmd.len[0] = size;
 249         return iwl_mvm_send_cmd(mvm, &hcmd);
 250 }

/* [<][>][^][v][top][bottom][index][help] */