offloading.c 8.4 KB

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