wcn36xx: Add ipv6 address tracking
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>
Sat, 5 Jun 2021 01:11:33 +0000 (02:11 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 14 Jun 2021 15:18:12 +0000 (18:18 +0300)
Taking code from iwlwifi this commit adds a standard callback for
ipv6_addr_change().

This callback allows wcn36xx to know the set of ipv6 addresses. Something
we need to know in order to get wowlan working with ipv6.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Tested-by: Benjamin Li <benl@squareup.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20210605011140.2004643-6-bryan.odonoghue@linaro.org
drivers/net/wireless/ath/wcn36xx/hal.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/wcn36xx.h

index b56c829..90333da 100644 (file)
@@ -3466,6 +3466,7 @@ struct wcn36xx_hal_rem_bcn_filter_req {
 #define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE             0x2
 #define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE        \
        (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE)
+#define WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX              0x02
 
 struct wcn36xx_hal_ns_offload_params {
        u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
index 9731fcb..240ecdd 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/rpmsg.h>
 #include <linux/soc/qcom/smem_state.h>
 #include <linux/soc/qcom/wcnss_ctrl.h>
+#include <net/ipv6.h>
 #include "wcn36xx.h"
 #include "testmode.h"
 
@@ -1208,6 +1209,34 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
        return ret;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct inet6_dev *idev)
+{
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+       struct inet6_ifaddr *ifa;
+       int idx = 0;
+
+       memset(vif_priv->tentative_addrs, 0, sizeof(vif_priv->tentative_addrs));
+
+       read_lock_bh(&idev->lock);
+       list_for_each_entry(ifa, &idev->addr_list, if_list) {
+               vif_priv->target_ipv6_addrs[idx] = ifa->addr;
+               if (ifa->flags & IFA_F_TENTATIVE)
+                       __set_bit(idx, vif_priv->tentative_addrs);
+               idx++;
+               if (idx >= WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)
+                       break;
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "%pI6 %s\n", &ifa->addr,
+                           (ifa->flags & IFA_F_TENTATIVE) ? "tentative" : NULL);
+       }
+       read_unlock_bh(&idev->lock);
+
+       vif_priv->num_target_ipv6_addrs = idx;
+}
+#endif
+
 static const struct ieee80211_ops wcn36xx_ops = {
        .start                  = wcn36xx_start,
        .stop                   = wcn36xx_stop,
@@ -1231,6 +1260,9 @@ static const struct ieee80211_ops wcn36xx_ops = {
        .sta_add                = wcn36xx_sta_add,
        .sta_remove             = wcn36xx_sta_remove,
        .ampdu_action           = wcn36xx_ampdu_action,
+#if IS_ENABLED(CONFIG_IPV6)
+       .ipv6_addr_change       = wcn36xx_ipv6_addr_change,
+#endif
 
        CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd)
 };
index 71fa999..5a51146 100644 (file)
@@ -18,6 +18,7 @@
 #define _WCN36XX_H_
 
 #include <linux/completion.h>
+#include <linux/in6.h>
 #include <linux/printk.h>
 #include <linux/spinlock.h>
 #include <net/mac80211.h>
@@ -136,6 +137,13 @@ struct wcn36xx_vif {
        u8 self_dpu_desc_index;
        u8 self_ucast_dpu_sign;
 
+#if IS_ENABLED(CONFIG_IPV6)
+       /* IPv6 addresses for WoWLAN */
+       struct in6_addr target_ipv6_addrs[WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX];
+       unsigned long tentative_addrs[BITS_TO_LONGS(WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)];
+       int num_target_ipv6_addrs;
+#endif
+
        struct list_head sta_list;
 };