diff options
Diffstat (limited to 'package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch')
-rw-r--r-- | package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch b/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch new file mode 100644 index 0000000..888ad5b --- /dev/null +++ b/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch @@ -0,0 +1,333 @@ +From: Franky Lin <frankyl@broadcom.com> +Date: Wed, 17 Feb 2016 11:26:55 +0100 +Subject: [PATCH] brcmfmac: add neighbor discovery offload ip address table + configuration + +Configure ipv6 address for neighbor discovery offload ip table in +firmware obtained through ipv6 address notification callback. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Franky Lin <frankyl@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp, + } + + static s32 +-brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) ++brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable) + { + s32 err; + u32 mode; +@@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf + enable, mode); + } + ++ err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable); ++ if (err) { ++ brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n", ++ enable, err); ++ err = 0; ++ } else ++ brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n", ++ enable, mode); ++ + return err; + } + +@@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct + brcmf_report_wowl_wakeind(wiphy, ifp); + brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); + brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, + cfg->wowl.pre_pmmode); + cfg->wowl.active = false; +@@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct + + brcmf_dbg(TRACE, "Suspend, wowl config.\n"); + +- brcmf_configure_arp_offload(ifp, false); ++ brcmf_configure_arp_nd_offload(ifp, false); + brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); + +@@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + + if (!mbss) { + brcmf_set_mpc(ifp, 0); +- brcmf_configure_arp_offload(ifp, false); ++ brcmf_configure_arp_nd_offload(ifp, false); + } + + /* find the RSN_IE */ +@@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + exit: + if ((err) && (!mbss)) { + brcmf_set_mpc(ifp, 1); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + } + return err; + } +@@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct + brcmf_err("bss_enable config failed %d\n", err); + } + brcmf_set_mpc(ifp, 1); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + brcmf_net_setcarrier(ifp, false); + +@@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct br + if (err) + goto default_conf_out; + +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + + cfg->dongle_up = true; + default_conf_out: +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -20,6 +20,8 @@ + #include <linux/inetdevice.h> + #include <net/cfg80211.h> + #include <net/rtnetlink.h> ++#include <net/addrconf.h> ++#include <net/ipv6.h> + #include <brcmu_utils.h> + #include <brcmu_wifi.h> + +@@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struc + } + } + ++#if IS_ENABLED(CONFIG_IPV6) ++static void _brcmf_update_ndtable(struct work_struct *work) ++{ ++ struct brcmf_if *ifp; ++ int i, ret; ++ ++ ifp = container_of(work, struct brcmf_if, ndoffload_work); ++ ++ /* clear the table in firmware */ ++ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0); ++ if (ret) { ++ brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret); ++ return; ++ } ++ ++ for (i = 0; i < ifp->ipv6addr_idx; i++) { ++ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip", ++ &ifp->ipv6_addr_tbl[i], ++ sizeof(struct in6_addr)); ++ if (ret) ++ brcmf_err("add nd ip err %d\n", ret); ++ } ++} ++#else ++static void _brcmf_update_ndtable(struct work_struct *work) ++{ ++} ++#endif ++ + static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) + { + struct brcmf_if *ifp = netdev_priv(ndev); +@@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *if + + INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); ++ INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable); + + if (rtnl_locked) + err = register_netdevice(ndev); +@@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pu + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); ++ cancel_work_sync(&ifp->ndoffload_work); + } + brcmf_net_detach(ifp->ndev); + } else { +@@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct + } + #endif + ++#if IS_ENABLED(CONFIG_IPV6) ++static int brcmf_inet6addr_changed(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub, ++ inet6addr_notifier); ++ struct inet6_ifaddr *ifa = data; ++ struct brcmf_if *ifp; ++ int i; ++ struct in6_addr *table; ++ ++ /* Only handle primary interface */ ++ ifp = drvr->iflist[0]; ++ if (!ifp) ++ return NOTIFY_DONE; ++ if (ifp->ndev != ifa->idev->dev) ++ return NOTIFY_DONE; ++ ++ table = ifp->ipv6_addr_tbl; ++ for (i = 0; i < NDOL_MAX_ENTRIES; i++) ++ if (ipv6_addr_equal(&ifa->addr, &table[i])) ++ break; ++ ++ switch (action) { ++ case NETDEV_UP: ++ if (i == NDOL_MAX_ENTRIES) { ++ if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) { ++ table[ifp->ipv6addr_idx++] = ifa->addr; ++ } else { ++ for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++) ++ table[i] = table[i + 1]; ++ table[NDOL_MAX_ENTRIES - 1] = ifa->addr; ++ } ++ } ++ break; ++ case NETDEV_DOWN: ++ if (i < NDOL_MAX_ENTRIES) ++ for (; i < ifp->ipv6addr_idx; i++) ++ table[i] = table[i + 1]; ++ break; ++ default: ++ break; ++ } ++ ++ schedule_work(&ifp->ndoffload_work); ++ ++ return NOTIFY_OK; ++} ++#endif ++ + int brcmf_attach(struct device *dev) + { + struct brcmf_pub *drvr = NULL; +@@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev) + #ifdef CONFIG_INET + drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed; + ret = register_inetaddr_notifier(&drvr->inetaddr_notifier); ++ if (ret) ++ goto fail; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed; ++ ret = register_inet6addr_notifier(&drvr->inet6addr_notifier); ++ if (ret) { ++ unregister_inetaddr_notifier(&drvr->inetaddr_notifier); ++ goto fail; ++ } + #endif ++#endif /* CONFIG_INET */ ++ ++ return 0; + + fail: +- if (ret < 0) { +- brcmf_err("failed: %d\n", ret); +- if (drvr->config) { +- brcmf_cfg80211_detach(drvr->config); +- drvr->config = NULL; +- } +- if (drvr->fws) { +- brcmf_fws_del_interface(ifp); +- brcmf_fws_deinit(drvr); +- } +- if (ifp) +- brcmf_net_detach(ifp->ndev); +- if (p2p_ifp) +- brcmf_net_detach(p2p_ifp->ndev); +- drvr->iflist[0] = NULL; +- drvr->iflist[1] = NULL; +- if (brcmf_ignoring_probe_fail(drvr)) +- ret = 0; +- return ret; ++ brcmf_err("failed: %d\n", ret); ++ if (drvr->config) { ++ brcmf_cfg80211_detach(drvr->config); ++ drvr->config = NULL; ++ } ++ if (drvr->fws) { ++ brcmf_fws_del_interface(ifp); ++ brcmf_fws_deinit(drvr); + } +- return 0; ++ if (ifp) ++ brcmf_net_detach(ifp->ndev); ++ if (p2p_ifp) ++ brcmf_net_detach(p2p_ifp->ndev); ++ drvr->iflist[0] = NULL; ++ drvr->iflist[1] = NULL; ++ if (brcmf_ignoring_probe_fail(drvr)) ++ ret = 0; ++ ++ return ret; + } + + void brcmf_bus_add_txhdrlen(struct device *dev, uint len) +@@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev) + unregister_inetaddr_notifier(&drvr->inetaddr_notifier); + #endif + ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&drvr->inet6addr_notifier); ++#endif ++ + /* stop firmware event handling */ + brcmf_fweh_detach(drvr); + if (drvr->config) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -48,6 +48,8 @@ + */ + #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 + ++#define NDOL_MAX_ENTRIES 8 ++ + /** + * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info + * +@@ -143,6 +145,7 @@ struct brcmf_pub { + #endif + + struct notifier_block inetaddr_notifier; ++ struct notifier_block inet6addr_notifier; + struct brcmf_mp_device *settings; + }; + +@@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason { + * @stats: interface specific network statistics. + * @setmacaddr_work: worker object for setting mac address. + * @multicast_work: worker object for multicast provisioning. ++ * @ndoffload_work: worker object for neighbor discovery offload configuration. + * @fws_desc: interface specific firmware-signalling descriptor. + * @ifidx: interface index in device firmware. + * @bsscfgidx: index of bss associated with this interface. +@@ -191,6 +195,7 @@ struct brcmf_if { + struct net_device_stats stats; + struct work_struct setmacaddr_work; + struct work_struct multicast_work; ++ struct work_struct ndoffload_work; + struct brcmf_fws_mac_descriptor *fws_desc; + int ifidx; + s32 bsscfgidx; +@@ -199,6 +204,8 @@ struct brcmf_if { + spinlock_t netif_stop_lock; + atomic_t pend_8021x_cnt; + wait_queue_head_t pend_8021x_wait; ++ struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES]; ++ u8 ipv6addr_idx; + }; + + struct brcmf_skb_reorder_data { |