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;
|
void *ptr;
|
||||||
int i;
|
int i;
|
||||||
struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload;
|
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_ns_offload *ns_tuple;
|
||||||
struct wmi_arp_offload *arp_tuple;
|
struct wmi_arp_offload *arp_tuple;
|
||||||
|
|
||||||
len = sizeof(*cmd) + sizeof(*tlv) +
|
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(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));
|
(sizeof(struct wmi_arp_offload) + sizeof(*tlv));
|
||||||
|
|
||||||
skb = ath10k_wmi_alloc_skb(ar, len);
|
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));
|
ptr += (sizeof(*tlv) + sizeof(*cmd));
|
||||||
tlv = ptr;
|
tlv = ptr;
|
||||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
|
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)));
|
(sizeof(struct wmi_ns_offload) + sizeof(*tlv)));
|
||||||
ptr += sizeof(*tlv);
|
ptr += sizeof(*tlv);
|
||||||
tlv = ptr;
|
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->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE);
|
||||||
tlv->len = __cpu_to_le16(sizeof(struct wmi_ns_offload));
|
tlv->len = __cpu_to_le16(sizeof(struct wmi_ns_offload));
|
||||||
ns_tuple = (struct wmi_ns_offload *)tlv->value;
|
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));
|
ptr += (sizeof(*tlv) + sizeof(struct wmi_ns_offload));
|
||||||
tlv = ptr;
|
tlv = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
|
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)));
|
(sizeof(struct wmi_arp_offload) + sizeof(*tlv)));
|
||||||
ptr += sizeof(*tlv);
|
ptr += sizeof(*tlv);
|
||||||
tlv = ptr;
|
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->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE);
|
||||||
tlv->len = __cpu_to_le16(sizeof(struct wmi_arp_offload));
|
tlv->len = __cpu_to_le16(sizeof(struct wmi_arp_offload));
|
||||||
arp_tuple = (struct wmi_arp_offload *)tlv->value;
|
arp_tuple = (struct wmi_arp_offload *)tlv->value;
|
||||||
if (arp->enable_offload && (i == 0)) {
|
if (arp->enable_offload && (i == 0)) {
|
||||||
arp_tuple->flags |=
|
arp_tuple->flags |=
|
||||||
__cpu_to_le32(WMI_ARPOFF_FLAGS_VALID);
|
__cpu_to_le32(WMI_ARP_NS_OFF_FLAGS_VALID);
|
||||||
memcpy(&arp_tuple->target_ipaddr,
|
memcpy(&arp_tuple->target_ipaddr,
|
||||||
&arp->params.ipv4_addr,
|
&arp->params.ipv4_addr,
|
||||||
sizeof(arp_tuple->target_ipaddr));
|
sizeof(arp_tuple->target_ipaddr));
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
#include <linux/ipv6.h>
|
#include <linux/ipv6.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2887,13 +2888,12 @@ struct wmi_start_scan_common {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* ARP-NS offload data structure */
|
/* ARP-NS offload data structure */
|
||||||
#define WMI_NSOFF_MAX_TARGET_IPS 2
|
#define WMI_NS_ARP_OFFLOAD 2
|
||||||
#define WMI_MAX_NS_OFFLOADS 2
|
#define WMI_ARP_NS_OFF_FLAGS_VALID BIT(0)
|
||||||
#define WMI_MAX_ARP_OFFLOADS 2
|
|
||||||
#define WMI_ARPOFF_FLAGS_VALID BIT(0)
|
|
||||||
#define WMI_IPV4_ARP_REPLY_OFFLOAD 0
|
#define WMI_IPV4_ARP_REPLY_OFFLOAD 0
|
||||||
#define WMI_ARP_NS_OFFLOAD_DISABLE 0
|
#define WMI_ARP_NS_OFFLOAD_DISABLE 0
|
||||||
#define WMI_ARP_NS_OFFLOAD_ENABLE 1
|
#define WMI_ARP_NS_OFFLOAD_ENABLE 1
|
||||||
|
#define WMI_NSOFF_IPV6_ANYCAST BIT(3)
|
||||||
|
|
||||||
struct wmi_ns_offload_info {
|
struct wmi_ns_offload_info {
|
||||||
struct in6_addr src_addr;
|
struct in6_addr src_addr;
|
||||||
|
@ -2902,7 +2902,7 @@ struct wmi_ns_offload_info {
|
||||||
struct wmi_mac_addr self_macaddr;
|
struct wmi_mac_addr self_macaddr;
|
||||||
u8 src_ipv6_addr_valid;
|
u8 src_ipv6_addr_valid;
|
||||||
struct in6_addr target_addr_valid;
|
struct in6_addr target_addr_valid;
|
||||||
struct in6_addr target_addr_ac_type;
|
struct in6_addr target_ipv6_ac;
|
||||||
u8 slot_idx;
|
u8 slot_idx;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@ -2914,13 +2914,13 @@ struct wmi_ns_arp_offload_req {
|
||||||
struct in_addr ipv4_addr;
|
struct in_addr ipv4_addr;
|
||||||
struct in6_addr ipv6_addr;
|
struct in6_addr ipv6_addr;
|
||||||
} params;
|
} params;
|
||||||
struct wmi_ns_offload_info offload_info;
|
struct wmi_ns_offload_info info;
|
||||||
struct wmi_mac_addr bssid;
|
struct wmi_mac_addr bssid;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wmi_ns_offload {
|
struct wmi_ns_offload {
|
||||||
__le32 flags;
|
__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 solicitation_ipaddr;
|
||||||
struct in6_addr remote_ipaddr;
|
struct in6_addr remote_ipaddr;
|
||||||
struct wmi_mac_addr target_mac;
|
struct wmi_mac_addr target_mac;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "mac.h"
|
#include "mac.h"
|
||||||
|
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
|
#include <net/addrconf.h>
|
||||||
#include "hif.h"
|
#include "hif.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
@ -231,6 +232,116 @@ static int ath10k_wow_wakeup(struct ath10k *ar)
|
||||||
return 0;
|
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
|
static int
|
||||||
ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif,
|
ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif,
|
||||||
bool enable_offload)
|
bool enable_offload)
|
||||||
|
@ -291,6 +402,13 @@ static int ath10k_wow_enable_ns_arp_offload(struct ath10k *ar, bool offload)
|
||||||
return ret;
|
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);
|
ret = ath10k_wmi_set_arp_ns_offload(ar, arvif);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_err(ar, "failed to send offload cmd, vdev: %d\n",
|
ath10k_err(ar, "failed to send offload cmd, vdev: %d\n",
|
||||||
|
|
Loading…
Add table
Reference in a new issue