Merge "ath10k: enable neighbor solicitation offload in wow suspend"
This commit is contained in:
commit
e718c5461b
3 changed files with 150 additions and 15 deletions
|
@ -3123,13 +3123,14 @@ ath10k_wmi_tlv_op_gen_set_arp_ns_offload(struct ath10k *ar,
|
|||
void *ptr;
|
||||
int i;
|
||||
struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload;
|
||||
struct wmi_ns_arp_offload_req *ns = &arvif->ns_offload;
|
||||
struct wmi_ns_offload *ns_tuple;
|
||||
struct wmi_arp_offload *arp_tuple;
|
||||
|
||||
len = sizeof(*cmd) + sizeof(*tlv) +
|
||||
sizeof(*tlv) + WMI_MAX_NS_OFFLOADS *
|
||||
sizeof(*tlv) + WMI_NS_ARP_OFFLOAD *
|
||||
(sizeof(struct wmi_ns_offload) + sizeof(*tlv)) +
|
||||
sizeof(*tlv) + WMI_MAX_ARP_OFFLOADS *
|
||||
sizeof(*tlv) + WMI_NS_ARP_OFFLOAD *
|
||||
(sizeof(struct wmi_arp_offload) + sizeof(*tlv));
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, len);
|
||||
|
@ -3147,33 +3148,49 @@ ath10k_wmi_tlv_op_gen_set_arp_ns_offload(struct ath10k *ar,
|
|||
ptr += (sizeof(*tlv) + sizeof(*cmd));
|
||||
tlv = ptr;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
|
||||
tlv->len = __cpu_to_le16(WMI_MAX_NS_OFFLOADS *
|
||||
tlv->len = __cpu_to_le16(WMI_NS_ARP_OFFLOAD *
|
||||
(sizeof(struct wmi_ns_offload) + sizeof(*tlv)));
|
||||
ptr += sizeof(*tlv);
|
||||
tlv = ptr;
|
||||
|
||||
for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) {
|
||||
for (i = 0; i < WMI_NS_ARP_OFFLOAD; i++) {
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE);
|
||||
tlv->len = __cpu_to_le16(sizeof(struct wmi_ns_offload));
|
||||
ns_tuple = (struct wmi_ns_offload *)tlv->value;
|
||||
ns_tuple->flags |= __cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE);
|
||||
if (ns->enable_offload) {
|
||||
ns_tuple->flags |=
|
||||
__cpu_to_le32(WMI_ARP_NS_OFF_FLAGS_VALID);
|
||||
if (ns->info.target_addr_valid.s6_addr[i]) {
|
||||
memcpy(&ns_tuple->target_ipaddr[0],
|
||||
&ns->info.target_addr[i],
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
memcpy(&ns_tuple->solicitation_ipaddr,
|
||||
&ns->info.self_addr[i], sizeof(struct in6_addr));
|
||||
if (ns->info.target_ipv6_ac.s6_addr[i] == IPV6_ADDR_ANY)
|
||||
ns_tuple->flags |=
|
||||
__cpu_to_le32(WMI_NSOFF_IPV6_ANYCAST);
|
||||
} else {
|
||||
ns_tuple->flags |=
|
||||
__cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE);
|
||||
}
|
||||
ptr += (sizeof(*tlv) + sizeof(struct wmi_ns_offload));
|
||||
tlv = ptr;
|
||||
}
|
||||
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
|
||||
tlv->len = __cpu_to_le16(WMI_MAX_ARP_OFFLOADS *
|
||||
tlv->len = __cpu_to_le16(WMI_NS_ARP_OFFLOAD *
|
||||
(sizeof(struct wmi_arp_offload) + sizeof(*tlv)));
|
||||
ptr += sizeof(*tlv);
|
||||
tlv = ptr;
|
||||
|
||||
for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) {
|
||||
for (i = 0; i < WMI_NS_ARP_OFFLOAD; i++) {
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE);
|
||||
tlv->len = __cpu_to_le16(sizeof(struct wmi_arp_offload));
|
||||
arp_tuple = (struct wmi_arp_offload *)tlv->value;
|
||||
if (arp->enable_offload && (i == 0)) {
|
||||
arp_tuple->flags |=
|
||||
__cpu_to_le32(WMI_ARPOFF_FLAGS_VALID);
|
||||
__cpu_to_le32(WMI_ARP_NS_OFF_FLAGS_VALID);
|
||||
memcpy(&arp_tuple->target_ipaddr,
|
||||
&arp->params.ipv4_addr,
|
||||
sizeof(arp_tuple->target_ipaddr));
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/in.h>
|
||||
|
||||
/*
|
||||
|
@ -2887,13 +2888,12 @@ struct wmi_start_scan_common {
|
|||
} __packed;
|
||||
|
||||
/* ARP-NS offload data structure */
|
||||
#define WMI_NSOFF_MAX_TARGET_IPS 2
|
||||
#define WMI_MAX_NS_OFFLOADS 2
|
||||
#define WMI_MAX_ARP_OFFLOADS 2
|
||||
#define WMI_ARPOFF_FLAGS_VALID BIT(0)
|
||||
#define WMI_NS_ARP_OFFLOAD 2
|
||||
#define WMI_ARP_NS_OFF_FLAGS_VALID BIT(0)
|
||||
#define WMI_IPV4_ARP_REPLY_OFFLOAD 0
|
||||
#define WMI_ARP_NS_OFFLOAD_DISABLE 0
|
||||
#define WMI_ARP_NS_OFFLOAD_ENABLE 1
|
||||
#define WMI_NSOFF_IPV6_ANYCAST BIT(3)
|
||||
|
||||
struct wmi_ns_offload_info {
|
||||
struct in6_addr src_addr;
|
||||
|
@ -2902,7 +2902,7 @@ struct wmi_ns_offload_info {
|
|||
struct wmi_mac_addr self_macaddr;
|
||||
u8 src_ipv6_addr_valid;
|
||||
struct in6_addr target_addr_valid;
|
||||
struct in6_addr target_addr_ac_type;
|
||||
struct in6_addr target_ipv6_ac;
|
||||
u8 slot_idx;
|
||||
} __packed;
|
||||
|
||||
|
@ -2914,13 +2914,13 @@ struct wmi_ns_arp_offload_req {
|
|||
struct in_addr ipv4_addr;
|
||||
struct in6_addr ipv6_addr;
|
||||
} params;
|
||||
struct wmi_ns_offload_info offload_info;
|
||||
struct wmi_ns_offload_info info;
|
||||
struct wmi_mac_addr bssid;
|
||||
} __packed;
|
||||
|
||||
struct wmi_ns_offload {
|
||||
__le32 flags;
|
||||
struct in6_addr target_ipaddr[WMI_NSOFF_MAX_TARGET_IPS];
|
||||
struct in6_addr target_ipaddr[WMI_NS_ARP_OFFLOAD];
|
||||
struct in6_addr solicitation_ipaddr;
|
||||
struct in6_addr remote_ipaddr;
|
||||
struct wmi_mac_addr target_mac;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mac.h"
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include <net/addrconf.h>
|
||||
#include "hif.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
@ -231,6 +232,116 @@ static int ath10k_wow_wakeup(struct ath10k *ar)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_wow_fill_vdev_ns_offload_struct(struct ath10k_vif *arvif,
|
||||
bool enable_offload)
|
||||
{
|
||||
struct in6_addr addr[TARGET_NUM_STATIONS];
|
||||
struct wmi_ns_arp_offload_req *ns;
|
||||
struct wireless_dev *wdev;
|
||||
struct inet6_dev *in6_dev;
|
||||
struct in6_addr addr_type;
|
||||
struct inet6_ifaddr *ifa;
|
||||
struct ifacaddr6 *ifaca;
|
||||
struct list_head *addr_list;
|
||||
u32 scope, count = 0;
|
||||
int i;
|
||||
|
||||
ns = &arvif->ns_offload;
|
||||
if (!enable_offload) {
|
||||
ns->offload_type = __cpu_to_le16(WMI_NS_ARP_OFFLOAD);
|
||||
ns->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_DISABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wdev = ieee80211_vif_to_wdev(arvif->vif);
|
||||
if (!wdev)
|
||||
return -ENODEV;
|
||||
|
||||
in6_dev = __in6_dev_get(wdev->netdev);
|
||||
if (!in6_dev)
|
||||
return -ENODEV;
|
||||
|
||||
memset(&addr, 0, TARGET_NUM_STATIONS * sizeof(struct in6_addr));
|
||||
memset(&addr_type, 0, sizeof(struct in6_addr));
|
||||
|
||||
/* Unicast Addresses */
|
||||
read_lock_bh(&in6_dev->lock);
|
||||
list_for_each(addr_list, &in6_dev->addr_list) {
|
||||
if (count >= TARGET_NUM_STATIONS) {
|
||||
read_unlock_bh(&in6_dev->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ifa = list_entry(addr_list, struct inet6_ifaddr, if_list);
|
||||
if (ifa->flags & IFA_F_DADFAILED)
|
||||
continue;
|
||||
scope = ipv6_addr_src_scope(&ifa->addr);
|
||||
switch (scope) {
|
||||
case IPV6_ADDR_SCOPE_GLOBAL:
|
||||
case IPV6_ADDR_SCOPE_LINKLOCAL:
|
||||
memcpy(&addr[count], &ifa->addr.s6_addr,
|
||||
sizeof(ifa->addr.s6_addr));
|
||||
addr_type.s6_addr[count] = IPV6_ADDR_UNICAST;
|
||||
count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Anycast Addresses */
|
||||
for (ifaca = in6_dev->ac_list; ifaca; ifaca = ifaca->aca_next) {
|
||||
if (count >= TARGET_NUM_STATIONS) {
|
||||
read_unlock_bh(&in6_dev->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scope = ipv6_addr_src_scope(&ifaca->aca_addr);
|
||||
switch (scope) {
|
||||
case IPV6_ADDR_SCOPE_GLOBAL:
|
||||
case IPV6_ADDR_SCOPE_LINKLOCAL:
|
||||
memcpy(&addr[count], &ifaca->aca_addr,
|
||||
sizeof(ifaca->aca_addr));
|
||||
addr_type.s6_addr[count] = IPV6_ADDR_ANY;
|
||||
count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&in6_dev->lock);
|
||||
|
||||
/* Filling up the request structure
|
||||
* Filling the self_addr with solicited address
|
||||
* A Solicited-Node multicast address is created by
|
||||
* taking the last 24 bits of a unicast or anycast
|
||||
* address and appending them to the prefix
|
||||
*
|
||||
* FF02:0000:0000:0000:0000:0001:FFXX:XXXX
|
||||
*
|
||||
* here XX is the unicast/anycast bits
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
ns->info.self_addr[i].s6_addr[0] = 0xFF;
|
||||
ns->info.self_addr[i].s6_addr[1] = 0x02;
|
||||
ns->info.self_addr[i].s6_addr[11] = 0x01;
|
||||
ns->info.self_addr[i].s6_addr[12] = 0xFF;
|
||||
ns->info.self_addr[i].s6_addr[13] = addr[i].s6_addr[13];
|
||||
ns->info.self_addr[i].s6_addr[14] = addr[i].s6_addr[14];
|
||||
ns->info.self_addr[i].s6_addr[15] = addr[i].s6_addr[15];
|
||||
ns->info.slot_idx = i;
|
||||
memcpy(&ns->info.target_addr[i], &addr[i],
|
||||
sizeof(struct in6_addr));
|
||||
ns->info.target_addr_valid.s6_addr[i] = 1;
|
||||
ns->info.target_ipv6_ac.s6_addr[i] = addr_type.s6_addr[i];
|
||||
memcpy(&ns->params.ipv6_addr, &ns->info.target_addr[i],
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
ns->offload_type = __cpu_to_le16(WMI_NS_ARP_OFFLOAD);
|
||||
ns->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_ENABLE);
|
||||
ns->num_ns_offload_count = __cpu_to_le16(count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif,
|
||||
bool enable_offload)
|
||||
|
@ -291,6 +402,13 @@ static int ath10k_wow_enable_ns_arp_offload(struct ath10k *ar, bool offload)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_wow_fill_vdev_ns_offload_struct(arvif, offload);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "NS-offload config failed, vdev: %d\n",
|
||||
arvif->vdev_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_set_arp_ns_offload(ar, arvif);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to send offload cmd, vdev: %d\n",
|
||||
|
|
Loading…
Add table
Reference in a new issue