mirror of https://gitee.com/openkylin/linux.git
brcmfmac: add arp offload ip address table configuration support
Obtain ipv4 address through inetaddr notification for ARP offload host ip table configuration. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@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>
This commit is contained in:
parent
f7b7caa488
commit
44129ed04b
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <brcmu_utils.h>
|
||||
|
@ -620,6 +621,8 @@ static int brcmf_netdev_stop(struct net_device *ndev)
|
|||
|
||||
brcmf_cfg80211_down(ndev);
|
||||
|
||||
brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
|
||||
|
||||
brcmf_net_setcarrier(ifp, false);
|
||||
|
||||
return 0;
|
||||
|
@ -940,6 +943,98 @@ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
|
|||
return available ? bsscfgidx : -ENOMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
#define ARPOL_MAX_ENTRIES 8
|
||||
static int brcmf_inetaddr_changed(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
|
||||
inetaddr_notifier);
|
||||
struct in_ifaddr *ifa = data;
|
||||
struct net_device *ndev = ifa->ifa_dev->dev;
|
||||
struct brcmf_if *ifp;
|
||||
int idx, i, ret;
|
||||
u32 val;
|
||||
__be32 addr_table[ARPOL_MAX_ENTRIES] = {0};
|
||||
|
||||
/* Find out if the notification is meant for us */
|
||||
for (idx = 0; idx < BRCMF_MAX_IFS; idx++) {
|
||||
ifp = drvr->iflist[idx];
|
||||
if (ifp && ifp->ndev == ndev)
|
||||
break;
|
||||
if (idx == BRCMF_MAX_IFS - 1)
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/* check if arp offload is supported */
|
||||
ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
|
||||
if (ret)
|
||||
return NOTIFY_OK;
|
||||
|
||||
/* old version only support primary index */
|
||||
ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
|
||||
if (ret)
|
||||
val = 1;
|
||||
if (val == 1)
|
||||
ifp = drvr->iflist[0];
|
||||
|
||||
/* retrieve the table from firmware */
|
||||
ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
|
||||
sizeof(addr_table));
|
||||
if (ret) {
|
||||
brcmf_err("fail to get arp ip table err:%d\n", ret);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
|
||||
if (ifa->ifa_address == addr_table[i])
|
||||
break;
|
||||
|
||||
switch (action) {
|
||||
case NETDEV_UP:
|
||||
if (i == ARPOL_MAX_ENTRIES) {
|
||||
brcmf_dbg(TRACE, "add %pI4 to arp table\n",
|
||||
&ifa->ifa_address);
|
||||
/* set it directly */
|
||||
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
|
||||
&ifa->ifa_address, sizeof(ifa->ifa_address));
|
||||
if (ret)
|
||||
brcmf_err("add arp ip err %d\n", ret);
|
||||
}
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
if (i < ARPOL_MAX_ENTRIES) {
|
||||
addr_table[i] = 0;
|
||||
brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
|
||||
&ifa->ifa_address);
|
||||
/* clear the table in firmware */
|
||||
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
|
||||
NULL, 0);
|
||||
if (ret) {
|
||||
brcmf_err("fail to clear arp ip table err:%d\n",
|
||||
ret);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
|
||||
if (addr_table[i] != 0) {
|
||||
brcmf_fil_iovar_data_set(ifp,
|
||||
"arp_hostip", &addr_table[i],
|
||||
sizeof(addr_table[i]));
|
||||
if (ret)
|
||||
brcmf_err("add arp ip err %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int brcmf_attach(struct device *dev)
|
||||
{
|
||||
struct brcmf_pub *drvr = NULL;
|
||||
|
@ -1068,6 +1163,15 @@ int brcmf_bus_start(struct device *dev)
|
|||
if (p2p_ifp)
|
||||
ret = brcmf_net_p2p_attach(p2p_ifp);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
|
||||
ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
|
||||
#endif
|
||||
|
||||
fail:
|
||||
if (ret < 0) {
|
||||
brcmf_err("failed: %d\n", ret);
|
||||
|
@ -1133,6 +1237,10 @@ void brcmf_detach(struct device *dev)
|
|||
if (drvr == NULL)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
|
||||
#endif
|
||||
|
||||
/* stop firmware event handling */
|
||||
brcmf_fweh_detach(drvr);
|
||||
if (drvr->config)
|
||||
|
|
|
@ -141,6 +141,8 @@ struct brcmf_pub {
|
|||
#ifdef DEBUG
|
||||
struct dentry *dbgfs_dir;
|
||||
#endif
|
||||
|
||||
struct notifier_block inetaddr_notifier;
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
|
Loading…
Reference in New Issue