AP: Add support for IPv4 neighbor entry management to the BSS bridge
This allows adding/deleting an IPv4 neighbor entry to/from the bridge, to which the BSS belongs. This commit adds the needed functionality in driver_nl80211.c for the Linux bridge implementation. In theory, this could be shared with multiple Linux driver interfaces, but for now, only the main nl80211 interface is supported. Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
This commit is contained in:
parent
6c6678e7a4
commit
71103bed42
3 changed files with 180 additions and 0 deletions
|
@ -280,6 +280,26 @@ static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
|
|||
return hapd->driver->status(hapd->drv_priv, buf, buflen);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
|
||||
be32 ipaddr, int prefixlen,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
|
||||
hapd->driver->br_add_ip_neigh == NULL)
|
||||
return -1;
|
||||
return hapd->driver->br_add_ip_neigh(hapd->drv_priv, ipaddr, prefixlen,
|
||||
addr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd,
|
||||
be32 ipaddr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
|
||||
hapd->driver->br_delete_ip_neigh == NULL)
|
||||
return -1;
|
||||
return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, ipaddr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
|
||||
int vendor_id, int subcmd,
|
||||
const u8 *data, size_t data_len,
|
||||
|
|
|
@ -2600,6 +2600,25 @@ struct wpa_driver_ops {
|
|||
int (*set_qos_map)(void *priv, const u8 *qos_map_set,
|
||||
u8 qos_map_set_len);
|
||||
|
||||
/**
|
||||
* br_add_ip_neigh - Add a neigh to the bridge ip neigh table
|
||||
* @priv: Private driver interface data
|
||||
* @ipaddr: IPv4 address for the neigh entry
|
||||
* @prefixlen: IPv4 address netmask prefix length
|
||||
* @addr: Corresponding MAC address
|
||||
* Returns: 0 on success, negative (<0) on failure
|
||||
*/
|
||||
int (*br_add_ip_neigh)(void *priv, be32 ipaddr, int prefixlen,
|
||||
const u8 *addr);
|
||||
|
||||
/**
|
||||
* br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
|
||||
* @priv: Private driver interface data
|
||||
* @ipaddr: IPv4 address for the neigh entry
|
||||
* Returns: 0 on success, negative (<0) on failure
|
||||
*/
|
||||
int (*br_delete_ip_neigh)(void *priv, be32 ipaddr);
|
||||
|
||||
/**
|
||||
* set_wowlan - Set wake-on-wireless triggers
|
||||
* @priv: Private driver interface data
|
||||
|
|
|
@ -8835,6 +8835,145 @@ nla_put_failure:
|
|||
#endif /* CONFIG_MESH */
|
||||
|
||||
|
||||
static int wpa_driver_br_add_ip_neigh(void *priv, be32 ipaddr,
|
||||
int prefixlen, const u8 *addr)
|
||||
{
|
||||
#ifdef CONFIG_LIBNL3_ROUTE
|
||||
struct i802_bss *bss = priv;
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
struct rtnl_neigh *rn;
|
||||
struct nl_addr *nl_ipaddr = NULL;
|
||||
struct nl_addr *nl_lladdr = NULL;
|
||||
int res;
|
||||
|
||||
if (ipaddr == 0 || prefixlen == 0 || !addr)
|
||||
return -EINVAL;
|
||||
|
||||
if (bss->br_ifindex == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: bridge must be set before adding an ip neigh to it");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!drv->rtnl_sk) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: nl_sock for NETLINK_ROUTE is not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rn = rtnl_neigh_alloc();
|
||||
if (rn == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* set the destination ip address for neigh */
|
||||
nl_ipaddr = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr));
|
||||
if (nl_ipaddr == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
|
||||
res = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
|
||||
res = rtnl_neigh_set_dst(rn, nl_ipaddr);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: neigh set destination addr failed");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* set the corresponding lladdr for neigh */
|
||||
nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
|
||||
if (nl_lladdr == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
|
||||
res = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
rtnl_neigh_set_lladdr(rn, nl_lladdr);
|
||||
|
||||
rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
|
||||
rtnl_neigh_set_state(rn, NUD_PERMANENT);
|
||||
|
||||
res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Adding bridge ip neigh failed: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
errout:
|
||||
if (nl_lladdr)
|
||||
nl_addr_put(nl_lladdr);
|
||||
if (nl_ipaddr)
|
||||
nl_addr_put(nl_ipaddr);
|
||||
if (rn)
|
||||
rtnl_neigh_put(rn);
|
||||
return res;
|
||||
#else /* CONFIG_LIBNL3_ROUTE */
|
||||
return -1;
|
||||
#endif /* CONFIG_LIBNL3_ROUTE */
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_br_delete_ip_neigh(void *priv, be32 ipaddr)
|
||||
{
|
||||
#ifdef CONFIG_LIBNL3_ROUTE
|
||||
struct i802_bss *bss = priv;
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
struct rtnl_neigh *rn;
|
||||
struct nl_addr *nl_ipaddr;
|
||||
int res;
|
||||
|
||||
if (ipaddr == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (bss->br_ifindex == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: bridge must be set to delete an ip neigh");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!drv->rtnl_sk) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: nl_sock for NETLINK_ROUTE is not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rn = rtnl_neigh_alloc();
|
||||
if (rn == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* set the destination ip address for neigh */
|
||||
nl_ipaddr = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr));
|
||||
if (nl_ipaddr == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
|
||||
res = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
res = rtnl_neigh_set_dst(rn, nl_ipaddr);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: neigh set destination addr failed");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
|
||||
|
||||
res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Deleting bridge ip neigh failed: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
errout:
|
||||
if (nl_ipaddr)
|
||||
nl_addr_put(nl_ipaddr);
|
||||
if (rn)
|
||||
rtnl_neigh_put(rn);
|
||||
return res;
|
||||
#else /* CONFIG_LIBNL3_ROUTE */
|
||||
return -1;
|
||||
#endif /* CONFIG_LIBNL3_ROUTE */
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||
.name = "nl80211",
|
||||
.desc = "Linux nl80211/cfg80211",
|
||||
|
@ -8933,4 +9072,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|||
.join_mesh = wpa_driver_nl80211_join_mesh,
|
||||
.leave_mesh = wpa_driver_nl80211_leave_mesh,
|
||||
#endif /* CONFIG_MESH */
|
||||
.br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
|
||||
.br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue