Skip to content

Commit

Permalink
brcmfmac: add arp offload ip address table configuration support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Franky Lin authored and Kalle Valo committed Jan 7, 2016
1 parent f7b7caa commit 44129ed
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
108 changes: 108 additions & 0 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ struct brcmf_pub {
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif

struct notifier_block inetaddr_notifier;
};

/* forward declarations */
Expand Down

0 comments on commit 44129ed

Please sign in to comment.