offloading.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. *
  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. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  23. * USA
  24. *
  25. * The full GNU General Public License is included in this distribution
  26. * in the file called COPYING.
  27. *
  28. * Contact Information:
  29. * Intel Linux Wireless <ilw@linux.intel.com>
  30. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  31. *
  32. * BSD LICENSE
  33. *
  34. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  35. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  36. * All rights reserved.
  37. *
  38. * Redistribution and use in source and binary forms, with or without
  39. * modification, are permitted provided that the following conditions
  40. * are met:
  41. *
  42. * * Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * * Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in
  46. * the documentation and/or other materials provided with the
  47. * distribution.
  48. * * Neither the name Intel Corporation nor the names of its
  49. * contributors may be used to endorse or promote products derived
  50. * from this software without specific prior written permission.
  51. *
  52. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  53. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  54. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  55. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  56. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  57. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  58. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  59. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  60. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  61. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  62. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  63. *
  64. *****************************************************************************/
  65. #include <net/ipv6.h>
  66. #include <net/addrconf.h>
  67. #include "mvm.h"
  68. void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
  69. struct iwl_wowlan_config_cmd *cmd)
  70. {
  71. int i;
  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. int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
  84. struct ieee80211_vif *vif,
  85. bool disable_offloading,
  86. u32 cmd_flags)
  87. {
  88. union {
  89. struct iwl_proto_offload_cmd_v1 v1;
  90. struct iwl_proto_offload_cmd_v2 v2;
  91. struct iwl_proto_offload_cmd_v3_small v3s;
  92. struct iwl_proto_offload_cmd_v3_large v3l;
  93. } cmd = {};
  94. struct iwl_host_cmd hcmd = {
  95. .id = PROT_OFFLOAD_CONFIG_CMD,
  96. .flags = cmd_flags,
  97. .data[0] = &cmd,
  98. .dataflags[0] = IWL_HCMD_DFL_DUP,
  99. };
  100. struct iwl_proto_offload_cmd_common *common;
  101. u32 enabled = 0, size;
  102. u32 capa_flags = mvm->fw->ucode_capa.flags;
  103. #if IS_ENABLED(CONFIG_IPV6)
  104. struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  105. int i;
  106. if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
  107. capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
  108. struct iwl_ns_config *nsc;
  109. struct iwl_targ_addr *addrs;
  110. int n_nsc, n_addrs;
  111. int c;
  112. if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
  113. nsc = cmd.v3s.ns_config;
  114. n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
  115. addrs = cmd.v3s.targ_addrs;
  116. n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
  117. } else {
  118. nsc = cmd.v3l.ns_config;
  119. n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
  120. addrs = cmd.v3l.targ_addrs;
  121. n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
  122. }
  123. if (mvmvif->num_target_ipv6_addrs)
  124. enabled |= IWL_D3_PROTO_OFFLOAD_NS;
  125. /*
  126. * For each address we have (and that will fit) fill a target
  127. * address struct and combine for NS offload structs with the
  128. * solicited node addresses.
  129. */
  130. for (i = 0, c = 0;
  131. i < mvmvif->num_target_ipv6_addrs &&
  132. i < n_addrs && c < n_nsc; i++) {
  133. struct in6_addr solicited_addr;
  134. int j;
  135. addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
  136. &solicited_addr);
  137. for (j = 0; j < c; j++)
  138. if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
  139. &solicited_addr) == 0)
  140. break;
  141. if (j == c)
  142. c++;
  143. addrs[i].addr = mvmvif->target_ipv6_addrs[i];
  144. addrs[i].config_num = cpu_to_le32(j);
  145. nsc[j].dest_ipv6_addr = solicited_addr;
  146. memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
  147. }
  148. if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
  149. cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
  150. else
  151. cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
  152. } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
  153. if (mvmvif->num_target_ipv6_addrs) {
  154. enabled |= IWL_D3_PROTO_OFFLOAD_NS;
  155. memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
  156. }
  157. BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
  158. sizeof(mvmvif->target_ipv6_addrs[0]));
  159. for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
  160. IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++)
  161. memcpy(cmd.v2.target_ipv6_addr[i],
  162. &mvmvif->target_ipv6_addrs[i],
  163. sizeof(cmd.v2.target_ipv6_addr[i]));
  164. } else {
  165. if (mvmvif->num_target_ipv6_addrs) {
  166. enabled |= IWL_D3_PROTO_OFFLOAD_NS;
  167. memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
  168. }
  169. BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
  170. sizeof(mvmvif->target_ipv6_addrs[0]));
  171. for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
  172. IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++)
  173. memcpy(cmd.v1.target_ipv6_addr[i],
  174. &mvmvif->target_ipv6_addrs[i],
  175. sizeof(cmd.v1.target_ipv6_addr[i]));
  176. }
  177. #endif
  178. if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
  179. common = &cmd.v3s.common;
  180. size = sizeof(cmd.v3s);
  181. } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
  182. common = &cmd.v3l.common;
  183. size = sizeof(cmd.v3l);
  184. } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
  185. common = &cmd.v2.common;
  186. size = sizeof(cmd.v2);
  187. } else {
  188. common = &cmd.v1.common;
  189. size = sizeof(cmd.v1);
  190. }
  191. if (vif->bss_conf.arp_addr_cnt) {
  192. enabled |= IWL_D3_PROTO_OFFLOAD_ARP;
  193. common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
  194. memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
  195. }
  196. if (!disable_offloading)
  197. common->enabled = cpu_to_le32(enabled);
  198. hcmd.len[0] = size;
  199. return iwl_mvm_send_cmd(mvm, &hcmd);
  200. }