aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-08-20 07:04:10 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-02 12:00:45 -0400
commitf7fc598931766a0609f33de249c17c067737425e (patch)
tree65e668f7e82131fe7a629c09c2e15c0ff238c5a0
parentf6fc57756bd8e89687b165280a9bdee290a7850a (diff)
iwlwifi: mvm: implement new IPv6 offload API
The firmware API for IPv6 NDP/NS offload has changed again. Implement support for the new API; this requires calculating the solicited node address for each "target" address as it's no longer ignored by the firmware. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c75
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h44
3 files changed, 118 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 8c2473e212d3..761794a5e916 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -84,6 +84,8 @@
84 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API 84 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
85 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element 85 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
86 * from the probe request template. 86 * from the probe request template.
87 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
88 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
87 * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. 89 * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
88 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API 90 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
89 */ 91 */
@@ -101,6 +103,8 @@ enum iwl_ucode_tlv_flag {
101 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), 103 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10),
102 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), 104 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11),
103 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), 105 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12),
106 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15),
107 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16),
104 IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), 108 IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
105 IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), 109 IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
106}; 110};
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 123a44f031a7..d08c12b930e5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -67,6 +67,7 @@
67#include <net/cfg80211.h> 67#include <net/cfg80211.h>
68#include <net/ipv6.h> 68#include <net/ipv6.h>
69#include <net/tcp.h> 69#include <net/tcp.h>
70#include <net/addrconf.h>
70#include "iwl-modparams.h" 71#include "iwl-modparams.h"
71#include "fw-api.h" 72#include "fw-api.h"
72#include "mvm.h" 73#include "mvm.h"
@@ -381,14 +382,74 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
381 union { 382 union {
382 struct iwl_proto_offload_cmd_v1 v1; 383 struct iwl_proto_offload_cmd_v1 v1;
383 struct iwl_proto_offload_cmd_v2 v2; 384 struct iwl_proto_offload_cmd_v2 v2;
385 struct iwl_proto_offload_cmd_v3_small v3s;
386 struct iwl_proto_offload_cmd_v3_large v3l;
384 } cmd = {}; 387 } cmd = {};
388 struct iwl_host_cmd hcmd = {
389 .id = PROT_OFFLOAD_CONFIG_CMD,
390 .flags = CMD_SYNC,
391 .data[0] = &cmd,
392 .dataflags[0] = IWL_HCMD_DFL_DUP,
393 };
385 struct iwl_proto_offload_cmd_common *common; 394 struct iwl_proto_offload_cmd_common *common;
386 u32 enabled = 0, size; 395 u32 enabled = 0, size;
396 u32 capa_flags = mvm->fw->ucode_capa.flags;
387#if IS_ENABLED(CONFIG_IPV6) 397#if IS_ENABLED(CONFIG_IPV6)
388 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 398 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
389 int i; 399 int i;
390 400
391 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { 401 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
402 capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
403 struct iwl_ns_config *nsc;
404 struct iwl_targ_addr *addrs;
405 int n_nsc, n_addrs;
406 int c;
407
408 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
409 nsc = cmd.v3s.ns_config;
410 n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
411 addrs = cmd.v3s.targ_addrs;
412 n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
413 } else {
414 nsc = cmd.v3l.ns_config;
415 n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
416 addrs = cmd.v3l.targ_addrs;
417 n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
418 }
419
420 if (mvmvif->num_target_ipv6_addrs)
421 enabled |= IWL_D3_PROTO_OFFLOAD_NS;
422
423 /*
424 * For each address we have (and that will fit) fill a target
425 * address struct and combine for NS offload structs with the
426 * solicited node addresses.
427 */
428 for (i = 0, c = 0;
429 i < mvmvif->num_target_ipv6_addrs &&
430 i < n_addrs && c < n_nsc; i++) {
431 struct in6_addr solicited_addr;
432 int j;
433
434 addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
435 &solicited_addr);
436 for (j = 0; j < c; j++)
437 if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
438 &solicited_addr) == 0)
439 break;
440 if (j == c)
441 c++;
442 addrs[i].addr = mvmvif->target_ipv6_addrs[i];
443 addrs[i].config_num = cpu_to_le32(j);
444 nsc[j].dest_ipv6_addr = solicited_addr;
445 memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
446 }
447
448 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
449 cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
450 else
451 cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
452 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
392 if (mvmvif->num_target_ipv6_addrs) { 453 if (mvmvif->num_target_ipv6_addrs) {
393 enabled |= IWL_D3_PROTO_OFFLOAD_NS; 454 enabled |= IWL_D3_PROTO_OFFLOAD_NS;
394 memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); 455 memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
@@ -419,7 +480,13 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
419 } 480 }
420#endif 481#endif
421 482
422 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { 483 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
484 common = &cmd.v3s.common;
485 size = sizeof(cmd.v3s);
486 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
487 common = &cmd.v3l.common;
488 size = sizeof(cmd.v3l);
489 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
423 common = &cmd.v2.common; 490 common = &cmd.v2.common;
424 size = sizeof(cmd.v2); 491 size = sizeof(cmd.v2);
425 } else { 492 } else {
@@ -438,8 +505,8 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
438 505
439 common->enabled = cpu_to_le32(enabled); 506 common->enabled = cpu_to_le32(enabled);
440 507
441 return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, 508 hcmd.len[0] = size;
442 size, &cmd); 509 return iwl_mvm_send_cmd(mvm, &hcmd);
443} 510}
444 511
445enum iwl_mvm_tcp_packet_type { 512enum iwl_mvm_tcp_packet_type {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index df72fcdf8170..1f7d65aaa87a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -100,7 +100,12 @@ enum iwl_proto_offloads {
100 100
101#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 101#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2
102#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 102#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6
103#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6 103#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L 12
104#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S 4
105#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 12
106
107#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L 4
108#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S 2
104 109
105/** 110/**
106 * struct iwl_proto_offload_cmd_common - ARP/NS offload common part 111 * struct iwl_proto_offload_cmd_common - ARP/NS offload common part
@@ -155,6 +160,43 @@ struct iwl_proto_offload_cmd_v2 {
155 u8 reserved2[3]; 160 u8 reserved2[3];
156} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ 161} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */
157 162
163struct iwl_ns_config {
164 struct in6_addr source_ipv6_addr;
165 struct in6_addr dest_ipv6_addr;
166 u8 target_mac_addr[ETH_ALEN];
167 __le16 reserved;
168} __packed; /* NS_OFFLOAD_CONFIG */
169
170struct iwl_targ_addr {
171 struct in6_addr addr;
172 __le32 config_num;
173} __packed; /* TARGET_IPV6_ADDRESS */
174
175/**
176 * struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration
177 * @common: common/IPv4 configuration
178 * @target_ipv6_addr: target IPv6 addresses
179 * @ns_config: NS offload configurations
180 */
181struct iwl_proto_offload_cmd_v3_small {
182 struct iwl_proto_offload_cmd_common common;
183 __le32 num_valid_ipv6_addrs;
184 struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S];
185 struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S];
186} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
187
188/**
189 * struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration
190 * @common: common/IPv4 configuration
191 * @target_ipv6_addr: target IPv6 addresses
192 * @ns_config: NS offload configurations
193 */
194struct iwl_proto_offload_cmd_v3_large {
195 struct iwl_proto_offload_cmd_common common;
196 __le32 num_valid_ipv6_addrs;
197 struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L];
198 struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L];
199} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
158 200
159/* 201/*
160 * WOWLAN_PATTERNS 202 * WOWLAN_PATTERNS