Loading drivers/net/wireless/ath/ath10k/wmi-tlv.c +25 −8 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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)); Loading drivers/net/wireless/ath/ath10k/wmi.h +7 −7 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <linux/types.h> #include <net/mac80211.h> #include <linux/ipv6.h> #include <net/ipv6.h> #include <linux/in.h> /* Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading drivers/net/wireless/ath/ath10k/wow.c +118 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "mac.h" #include <net/mac80211.h> #include <net/addrconf.h> #include "hif.h" #include "core.h" #include "debug.h" Loading Loading @@ -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) Loading Loading @@ -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 Loading
drivers/net/wireless/ath/ath10k/wmi-tlv.c +25 −8 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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)); Loading
drivers/net/wireless/ath/ath10k/wmi.h +7 −7 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <linux/types.h> #include <net/mac80211.h> #include <linux/ipv6.h> #include <net/ipv6.h> #include <linux/in.h> /* Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading
drivers/net/wireless/ath/ath10k/wow.c +118 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "mac.h" #include <net/mac80211.h> #include <net/addrconf.h> #include "hif.h" #include "core.h" #include "debug.h" Loading Loading @@ -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) Loading Loading @@ -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