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,
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
* @triggers: wowlan triggers
#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",
.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,
};