iwlwifi: mvm: support six IPv6 addresses in D3
Newer firmware supports offloading more IPv6 addresses for NDP, adjust the code to send the correct command depending on the firmware capability. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
88f2fd7300
commit
5369d6c167
|
@ -76,6 +76,8 @@
|
||||||
* @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
|
* @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
|
||||||
* @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
|
* @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
|
||||||
* @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
|
* @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
|
||||||
|
* @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
|
||||||
|
* (rather than two) IPv6 addresses
|
||||||
*/
|
*/
|
||||||
enum iwl_ucode_tlv_flag {
|
enum iwl_ucode_tlv_flag {
|
||||||
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
|
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
|
||||||
|
@ -85,6 +87,7 @@ enum iwl_ucode_tlv_flag {
|
||||||
IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
|
IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
|
||||||
IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6),
|
IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6),
|
||||||
IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8),
|
IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8),
|
||||||
|
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The default calibrate table size if not specified by firmware file */
|
/* The default calibrate table size if not specified by firmware file */
|
||||||
|
|
|
@ -105,7 +105,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
|
||||||
list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
||||||
mvmvif->target_ipv6_addrs[idx] = ifa->addr;
|
mvmvif->target_ipv6_addrs[idx] = ifa->addr;
|
||||||
idx++;
|
idx++;
|
||||||
if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS)
|
if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
|
@ -373,36 +373,68 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
|
||||||
static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct iwl_proto_offload_cmd cmd = {};
|
union {
|
||||||
|
struct iwl_proto_offload_cmd_v1 v1;
|
||||||
|
struct iwl_proto_offload_cmd_v2 v2;
|
||||||
|
} cmd = {};
|
||||||
|
struct iwl_proto_offload_cmd_common *common;
|
||||||
|
u32 enabled = 0, size;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mvmvif->num_target_ipv6_addrs) {
|
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||||
cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS);
|
if (mvmvif->num_target_ipv6_addrs) {
|
||||||
memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN);
|
enabled |= IWL_D3_PROTO_OFFLOAD_NS;
|
||||||
|
memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
|
||||||
|
sizeof(mvmvif->target_ipv6_addrs[0]));
|
||||||
|
|
||||||
|
for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
|
||||||
|
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++)
|
||||||
|
memcpy(cmd.v2.target_ipv6_addr[i],
|
||||||
|
&mvmvif->target_ipv6_addrs[i],
|
||||||
|
sizeof(cmd.v2.target_ipv6_addr[i]));
|
||||||
|
} else {
|
||||||
|
if (mvmvif->num_target_ipv6_addrs) {
|
||||||
|
enabled |= IWL_D3_PROTO_OFFLOAD_NS;
|
||||||
|
memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
|
||||||
|
sizeof(mvmvif->target_ipv6_addrs[0]));
|
||||||
|
|
||||||
|
for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
|
||||||
|
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++)
|
||||||
|
memcpy(cmd.v1.target_ipv6_addr[i],
|
||||||
|
&mvmvif->target_ipv6_addrs[i],
|
||||||
|
sizeof(cmd.v1.target_ipv6_addr[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) !=
|
|
||||||
sizeof(mvmvif->target_ipv6_addrs[i]));
|
|
||||||
|
|
||||||
for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++)
|
|
||||||
memcpy(cmd.target_ipv6_addr[i],
|
|
||||||
&mvmvif->target_ipv6_addrs[i],
|
|
||||||
sizeof(cmd.target_ipv6_addr[i]));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (vif->bss_conf.arp_addr_cnt) {
|
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||||
cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP);
|
common = &cmd.v2.common;
|
||||||
cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
|
size = sizeof(cmd.v2);
|
||||||
memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN);
|
} else {
|
||||||
|
common = &cmd.v1.common;
|
||||||
|
size = sizeof(cmd.v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd.enabled)
|
if (vif->bss_conf.arp_addr_cnt) {
|
||||||
|
enabled |= IWL_D3_PROTO_OFFLOAD_ARP;
|
||||||
|
common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
|
||||||
|
memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
common->enabled = cpu_to_le32(enabled);
|
||||||
|
|
||||||
return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
|
return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
|
||||||
sizeof(cmd), &cmd);
|
size, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum iwl_mvm_tcp_packet_type {
|
enum iwl_mvm_tcp_packet_type {
|
||||||
|
|
|
@ -98,34 +98,63 @@ enum iwl_proto_offloads {
|
||||||
IWL_D3_PROTO_OFFLOAD_NS = BIT(1),
|
IWL_D3_PROTO_OFFLOAD_NS = BIT(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2
|
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2
|
||||||
|
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6
|
||||||
|
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct iwl_proto_offload_cmd - ARP/NS offload configuration
|
* struct iwl_proto_offload_cmd_common - ARP/NS offload common part
|
||||||
* @enabled: enable flags
|
* @enabled: enable flags
|
||||||
* @remote_ipv4_addr: remote address to answer to (or zero if all)
|
* @remote_ipv4_addr: remote address to answer to (or zero if all)
|
||||||
* @host_ipv4_addr: our IPv4 address to respond to queries for
|
* @host_ipv4_addr: our IPv4 address to respond to queries for
|
||||||
* @arp_mac_addr: our MAC address for ARP responses
|
* @arp_mac_addr: our MAC address for ARP responses
|
||||||
|
* @reserved: unused
|
||||||
|
*/
|
||||||
|
struct iwl_proto_offload_cmd_common {
|
||||||
|
__le32 enabled;
|
||||||
|
__be32 remote_ipv4_addr;
|
||||||
|
__be32 host_ipv4_addr;
|
||||||
|
u8 arp_mac_addr[ETH_ALEN];
|
||||||
|
__le16 reserved;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_proto_offload_cmd_v1 - ARP/NS offload configuration
|
||||||
|
* @common: common/IPv4 configuration
|
||||||
* @remote_ipv6_addr: remote address to answer to (or zero if all)
|
* @remote_ipv6_addr: remote address to answer to (or zero if all)
|
||||||
* @solicited_node_ipv6_addr: broken -- solicited node address exists
|
* @solicited_node_ipv6_addr: broken -- solicited node address exists
|
||||||
* for each target address
|
* for each target address
|
||||||
* @target_ipv6_addr: our target addresses
|
* @target_ipv6_addr: our target addresses
|
||||||
* @ndp_mac_addr: neighbor soliciation response MAC address
|
* @ndp_mac_addr: neighbor soliciation response MAC address
|
||||||
*/
|
*/
|
||||||
struct iwl_proto_offload_cmd {
|
struct iwl_proto_offload_cmd_v1 {
|
||||||
__le32 enabled;
|
struct iwl_proto_offload_cmd_common common;
|
||||||
__be32 remote_ipv4_addr;
|
|
||||||
__be32 host_ipv4_addr;
|
|
||||||
u8 arp_mac_addr[ETH_ALEN];
|
|
||||||
__le16 reserved1;
|
|
||||||
|
|
||||||
u8 remote_ipv6_addr[16];
|
u8 remote_ipv6_addr[16];
|
||||||
u8 solicited_node_ipv6_addr[16];
|
u8 solicited_node_ipv6_addr[16];
|
||||||
u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16];
|
u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1][16];
|
||||||
u8 ndp_mac_addr[ETH_ALEN];
|
u8 ndp_mac_addr[ETH_ALEN];
|
||||||
__le16 reserved2;
|
__le16 reserved2;
|
||||||
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */
|
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_proto_offload_cmd_v2 - ARP/NS offload configuration
|
||||||
|
* @common: common/IPv4 configuration
|
||||||
|
* @remote_ipv6_addr: remote address to answer to (or zero if all)
|
||||||
|
* @solicited_node_ipv6_addr: broken -- solicited node address exists
|
||||||
|
* for each target address
|
||||||
|
* @target_ipv6_addr: our target addresses
|
||||||
|
* @ndp_mac_addr: neighbor soliciation response MAC address
|
||||||
|
*/
|
||||||
|
struct iwl_proto_offload_cmd_v2 {
|
||||||
|
struct iwl_proto_offload_cmd_common common;
|
||||||
|
u8 remote_ipv6_addr[16];
|
||||||
|
u8 solicited_node_ipv6_addr[16];
|
||||||
|
u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16];
|
||||||
|
u8 ndp_mac_addr[ETH_ALEN];
|
||||||
|
u8 numValidIPv6Addresses;
|
||||||
|
u8 reserved2[3];
|
||||||
|
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WOWLAN_PATTERNS
|
* WOWLAN_PATTERNS
|
||||||
|
|
|
@ -282,7 +282,7 @@ struct iwl_mvm_vif {
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
/* IPv6 addresses for WoWLAN */
|
/* IPv6 addresses for WoWLAN */
|
||||||
struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS];
|
struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
|
||||||
int num_target_ipv6_addrs;
|
int num_target_ipv6_addrs;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue