This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 8eaefd24246ab707b3cf831bd530537550bbfba0
Author: meijian <[email protected]>
AuthorDate: Tue Apr 16 17:19:33 2024 +0800

    net/netlink: Add RTM neigh notify support
    
    Signed-off-by: meijian <[email protected]>
---
 net/arp/arp_table.c         |  89 +++++++++++++---
 net/neighbor/neighbor_add.c |  25 +++++
 net/netlink/netlink.h       |  20 ++++
 net/netlink/netlink_route.c | 255 ++++++++++++++++++++++++++++++--------------
 4 files changed, 295 insertions(+), 94 deletions(-)

diff --git a/net/arp/arp_table.c b/net/arp/arp_table.c
index cfba3d2d67..5b4c691f3c 100644
--- a/net/arp/arp_table.c
+++ b/net/arp/arp_table.c
@@ -61,6 +61,7 @@
 #include <nuttx/net/ip.h>
 
 #include "netdev/netdev.h"
+#include "netlink/netlink.h"
 #include "arp/arp.h"
 
 #ifdef CONFIG_NET_ARP
@@ -208,6 +209,37 @@ static FAR struct arp_entry_s *arp_lookup(in_addr_t ipaddr,
   return NULL;
 }
 
+/****************************************************************************
+ * Name: arp_get_arpreq
+ *
+ * Description:
+ *   Translate (struct arp_entry_s) to (struct arpreq) for netlink notify.
+ *
+ * Input Parameters:
+ *   output - Location to return the ARP table copy
+ *   input  - The arp entry in table
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NETLINK_ROUTE
+static void arp_get_arpreq(FAR struct arpreq *output,
+                           FAR struct arp_entry_s *input)
+{
+  FAR struct sockaddr_in *outaddr;
+
+  DEBUGASSERT(output != NULL && input != NULL);
+
+  outaddr = (FAR struct sockaddr_in *)&output->arp_pa;
+  outaddr->sin_family      = AF_INET;
+  outaddr->sin_port        = 0;
+  outaddr->sin_addr.s_addr = input->at_ipaddr;
+  memcpy(output->arp_ha.sa_data, input->at_ethaddr.ether_addr_octet,
+         sizeof(struct ether_addr));
+  strlcpy((FAR char *)output->arp_dev, input->at_dev->d_ifname,
+          sizeof(output->arp_dev));
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -237,6 +269,11 @@ int arp_update(FAR struct net_driver_s *dev, in_addr_t 
ipaddr,
                FAR const uint8_t *ethaddr)
 {
   FAR struct arp_entry_s *tabptr = &g_arptable[0];
+#ifdef CONFIG_NETLINK_ROUTE
+  struct arpreq arp_notify;
+  bool found = false;
+  bool new_entry;
+#endif
   int i;
 
   /* Walk through the ARP mapping table and try to find an entry to
@@ -257,6 +294,9 @@ int arp_update(FAR struct net_driver_s *dev, in_addr_t 
ipaddr,
           /* An old entry found, break. */
 
           tabptr = &g_arptable[i];
+#ifdef CONFIG_NETLINK_ROUTE
+          found = true;
+#endif
           break;
         }
       else
@@ -267,6 +307,21 @@ int arp_update(FAR struct net_driver_s *dev, in_addr_t 
ipaddr,
         }
     }
 
+  /* When overwite old entry, notify old entry RTM_DELNEIGH */
+
+#ifdef CONFIG_NETLINK_ROUTE
+  if (!found && tabptr->at_ipaddr != 0)
+    {
+      arp_get_arpreq(&arp_notify, tabptr);
+      netlink_neigh_notify(&arp_notify, RTM_DELNEIGH, AF_INET);
+    }
+
+  /* Need to notify when entry is not found or changes in table */
+
+  new_entry = !found || memcmp(tabptr->at_ethaddr.ether_addr_octet,
+                               ethaddr, ETHER_ADDR_LEN) != 0;
+#endif
+
   /* Now, tabptr is the ARP table entry which we will fill with the new
    * information.
    */
@@ -275,6 +330,17 @@ int arp_update(FAR struct net_driver_s *dev, in_addr_t 
ipaddr,
   memcpy(tabptr->at_ethaddr.ether_addr_octet, ethaddr, ETHER_ADDR_LEN);
   tabptr->at_dev = dev;
   tabptr->at_time = clock_systime_ticks();
+
+  /* Notify the new entry */
+
+#ifdef CONFIG_NETLINK_ROUTE
+  if (new_entry)
+    {
+      arp_get_arpreq(&arp_notify, tabptr);
+      netlink_neigh_notify(&arp_notify, RTM_NEWNEIGH, AF_INET);
+    }
+#endif
+
   return OK;
 }
 
@@ -392,12 +458,21 @@ int arp_find(in_addr_t ipaddr, FAR uint8_t *ethaddr,
 int arp_delete(in_addr_t ipaddr, FAR struct net_driver_s *dev)
 {
   FAR struct arp_entry_s *tabptr;
-
+#ifdef CONFIG_NETLINK_ROUTE
+  struct arpreq arp_notify;
+#endif
   /* Check if the IPv4 address is in the ARP table. */
 
   tabptr = arp_lookup(ipaddr, dev);
   if (tabptr != NULL)
     {
+      /* Notify to netlink */
+
+#ifdef CONFIG_NETLINK_ROUTE
+      arp_get_arpreq(&arp_notify, tabptr);
+      netlink_neigh_notify(&arp_notify, RTM_DELNEIGH, AF_INET);
+#endif
+
       /* Yes.. Set the IP address to zero to "delete" it */
 
       tabptr->at_ipaddr = 0;
@@ -459,7 +534,6 @@ unsigned int arp_snapshot(FAR struct arpreq *snapshot,
                           unsigned int nentries)
 {
   FAR struct arp_entry_s *tabptr;
-  FAR struct sockaddr_in *outaddr;
   clock_t now;
   unsigned int ncopied;
   int i;
@@ -474,16 +548,7 @@ unsigned int arp_snapshot(FAR struct arpreq *snapshot,
       if (tabptr->at_ipaddr != 0 &&
           now - tabptr->at_time <= ARP_MAXAGE_TICK)
         {
-          outaddr = (FAR struct sockaddr_in *)&snapshot[ncopied].arp_pa;
-          outaddr->sin_family      = AF_INET;
-          outaddr->sin_port        = 0;
-          outaddr->sin_addr.s_addr = tabptr->at_ipaddr;
-          memcpy(snapshot[ncopied].arp_ha.sa_data,
-                 tabptr->at_ethaddr.ether_addr_octet,
-                 sizeof(struct ether_addr));
-          strlcpy((FAR char *)snapshot[ncopied].arp_dev,
-                  tabptr->at_dev->d_ifname,
-                  sizeof(snapshot[ncopied].arp_dev));
+          arp_get_arpreq(&snapshot[ncopied], tabptr);
           ncopied++;
         }
     }
diff --git a/net/neighbor/neighbor_add.c b/net/neighbor/neighbor_add.c
index 49801c5541..6257f6abb2 100644
--- a/net/neighbor/neighbor_add.c
+++ b/net/neighbor/neighbor_add.c
@@ -36,6 +36,7 @@
 #include <nuttx/net/neighbor.h>
 
 #include "netdev/netdev.h"
+#include "netlink/netlink.h"
 #include "neighbor/neighbor.h"
 
 /****************************************************************************
@@ -65,6 +66,8 @@ void neighbor_add(FAR struct net_driver_s *dev, FAR 
net_ipv6addr_t ipaddr,
   uint8_t lltype;
   clock_t oldest_time;
   int     oldest_ndx;
+  bool    found = false;
+  bool    new_entry;
   int     i;
 
   DEBUGASSERT(dev != NULL && addr != NULL);
@@ -85,6 +88,7 @@ void neighbor_add(FAR struct net_driver_s *dev, FAR 
net_ipv6addr_t ipaddr,
           net_ipv6addr_cmp(g_neighbors[i].ne_ipaddr, ipaddr))
         {
           oldest_ndx = i;
+          found = true;
           break;
         }
 
@@ -95,6 +99,19 @@ void neighbor_add(FAR struct net_driver_s *dev, FAR 
net_ipv6addr_t ipaddr,
         }
     }
 
+  /* When overwite old entry, need to notify RTM_DELNEIGH */
+
+  if (!found && g_neighbors[oldest_ndx].ne_time != 0)
+    {
+      netlink_neigh_notify(&g_neighbors[oldest_ndx], RTM_DELNEIGH,
+                           AF_INET6);
+    }
+
+  /* Need to notify when entry is not found or changes in table */
+
+  new_entry = !found || memcmp(&g_neighbors[oldest_ndx].ne_addr.u, addr,
+                             g_neighbors[oldest_ndx].ne_addr.na_llsize) != 0;
+
   /* Use the oldest or first free entry (either pointed to by the
    * "oldest_ndx" variable).
    */
@@ -109,6 +126,14 @@ void neighbor_add(FAR struct net_driver_s *dev, FAR 
net_ipv6addr_t ipaddr,
   memcpy(&g_neighbors[oldest_ndx].ne_addr.u, addr,
          g_neighbors[oldest_ndx].ne_addr.na_llsize);
 
+  /* Notify the new entry */
+
+  if (new_entry)
+    {
+      netlink_neigh_notify(&g_neighbors[oldest_ndx], RTM_NEWNEIGH,
+                           AF_INET6);
+    }
+
   /* Dump the contents of the new entry */
 
   neighbor_dumpentry("Added entry", &g_neighbors[oldest_ndx]);
diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h
index 474a898c16..fd1f81e4b3 100644
--- a/net/netlink/netlink.h
+++ b/net/netlink/netlink.h
@@ -47,6 +47,7 @@
 #  define netlink_device_notify(dev)
 #  define netlink_device_notify_ipaddr(dev, type, domain, addr, preflen)
 #  define netlink_route_notify(route, type, domain)
+#  define netlink_neigh_notify(neigh, type, domain)
 #endif
 
 #ifdef CONFIG_NET_NETLINK
@@ -532,6 +533,25 @@ void netlink_device_notify_ipaddr(FAR struct net_driver_s 
*dev,
 void netlink_route_notify(FAR const void *route, int type, int domain);
 #endif
 
+/****************************************************************************
+ * Name: netlink_neigh_notify()
+ *
+ * Description:
+ *   Perform the neigh broadcast for the NETLINK_ROUTE protocol.
+ *
+ * Input Parameters:
+ *   neigh  - The ARP entry or neighbour entry
+ *   type   - The type of the message, RTM_*NEIGH
+ *   domain - The domain of the message
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NETLINK_DISABLE_GETNEIGH)
+#  define netlink_neigh_notify(neigh, type, domain)
+#else
+void netlink_neigh_notify(FAR const void *neigh, int type, int domain);
+#endif
+
 /****************************************************************************
  * Name: nla_next
  *
diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c
index e91241a1d0..24ee4cddda 100644
--- a/net/netlink/netlink_route.c
+++ b/net/netlink/netlink_route.c
@@ -489,7 +489,7 @@ static int netlink_get_devlist(NETLINK_HANDLE handle,
 #endif
 
 /****************************************************************************
- * Name: netlink_get_arptable()
+ * Name: netlink_fill_arptable()
  *
  * Description:
  *   Return the entire ARP table.
@@ -497,45 +497,20 @@ static int netlink_get_devlist(NETLINK_HANDLE handle,
  ****************************************************************************/
 
 #if defined(CONFIG_NET_ARP) && !defined(CONFIG_NETLINK_DISABLE_GETNEIGH)
-static int netlink_get_arptable(NETLINK_HANDLE handle,
-                              FAR const struct nlroute_sendto_request_s *req)
+static size_t netlink_fill_arptable(
+                              FAR struct getneigh_recvfrom_rsplist_s **entry)
 {
-  FAR struct getneigh_recvfrom_rsplist_s *entry;
   unsigned int ncopied;
   size_t allocsize;
   size_t tabsize;
   size_t rspsize;
 
-  /* Preallocate memory to hold the maximum sized ARP table
-   * REVISIT:  This is probably excessively large and could cause false
-   * memory out conditions.  A better approach would be to actually count
-   * the number of valid entries in the ARP table.
-   */
-
-  tabsize   = CONFIG_NET_ARPTAB_SIZE * sizeof(struct arpreq);
-  rspsize   = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize);
-  allocsize = SIZEOF_NLROUTE_RECVFROM_RSPLIST_S(tabsize);
-
-  entry = kmm_zalloc(allocsize);
-  if (entry == NULL)
-    {
-      nerr("ERROR: Failed to allocate response buffer.\n");
-      return -ENOMEM;
-    }
-
-  /* Populate the entry */
-
-  memcpy(&entry->payload.hdr, &req->hdr, sizeof(struct nlmsghdr));
-  entry->payload.hdr.nlmsg_len  = rspsize;
-  entry->payload.msg.ndm_family = req->gen.rtgen_family;
-  entry->payload.attr.rta_len   = RTA_LENGTH(tabsize);
-
   /* Lock the network so that the ARP table will be stable, then copy
    * the ARP table into the allocated memory.
    */
 
   net_lock();
-  ncopied = arp_snapshot((FAR struct arpreq *)entry->payload.data,
+  ncopied = arp_snapshot((FAR struct arpreq *)(*entry)->payload.data,
                          CONFIG_NET_ARPTAB_SIZE);
   net_unlock();
 
@@ -543,7 +518,7 @@ static int netlink_get_arptable(NETLINK_HANDLE handle,
    * we can trim the allocation.
    */
 
-  if (ncopied < CONFIG_NET_ARPTAB_SIZE)
+  if (ncopied > 0)
     {
       FAR struct getneigh_recvfrom_rsplist_s *newentry;
 
@@ -551,27 +526,23 @@ static int netlink_get_arptable(NETLINK_HANDLE handle,
       rspsize = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize);
       allocsize = SIZEOF_NLROUTE_RECVFROM_RSPLIST_S(tabsize);
 
-      newentry = (FAR struct getneigh_recvfrom_rsplist_s *)
-        kmm_realloc(entry, allocsize);
+      newentry = kmm_realloc(*entry, allocsize);
 
       if (newentry != NULL)
         {
-           entry = newentry;
+          *entry = newentry;
         }
 
-      entry->payload.hdr.nlmsg_len = rspsize;
-      entry->payload.attr.rta_len  = RTA_LENGTH(tabsize);
+      (*entry)->payload.hdr.nlmsg_len = rspsize;
+      (*entry)->payload.attr.rta_len  = RTA_LENGTH(tabsize);
     }
 
-  /* Finally, add the data to the list of pending responses */
-
-  netlink_add_response(handle, (FAR struct netlink_response_s *)entry);
-  return OK;
+  return ncopied;
 }
 #endif
 
 /****************************************************************************
- * Name: netlink_get_nbtable()
+ * Name: netlink_fill_nbtable()
  *
  * Description:
  *   Return the entire IPv6 neighbor table.
@@ -579,55 +550,29 @@ static int netlink_get_arptable(NETLINK_HANDLE handle,
  ****************************************************************************/
 
 #if defined(CONFIG_NET_IPv6) && !defined(CONFIG_NETLINK_DISABLE_GETNEIGH)
-static int netlink_get_nbtable(NETLINK_HANDLE handle,
-                              FAR const struct nlroute_sendto_request_s *req)
+static size_t netlink_fill_nbtable(
+                              FAR struct getneigh_recvfrom_rsplist_s **entry)
 {
-  FAR struct getneigh_recvfrom_rsplist_s *entry;
   unsigned int ncopied;
   size_t allocsize;
   size_t tabsize;
   size_t rspsize;
 
-  /* Preallocate memory to hold the maximum sized Neighbor table
-   * REVISIT:  This is probably excessively large and could cause false
-   * memory out conditions.  A better approach would be to actually count
-   * the number of valid entries in the Neighbor table.
-   */
-
-  tabsize   = CONFIG_NET_IPv6_NCONF_ENTRIES *
-              sizeof(struct neighbor_entry_s);
-  rspsize   = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize);
-  allocsize = SIZEOF_NLROUTE_RECVFROM_RSPLIST_S(tabsize);
-
-  entry = kmm_zalloc(allocsize);
-  if (entry == NULL)
-    {
-      nerr("ERROR: Failed to allocate response buffer.\n");
-      return -ENOMEM;
-    }
-
-  /* Populate the entry */
-
-  memcpy(&entry->payload.hdr, &req->hdr, sizeof(struct nlmsghdr));
-  entry->payload.hdr.nlmsg_len  = rspsize;
-  entry->payload.msg.ndm_family = req->gen.rtgen_family;
-  entry->payload.attr.rta_len   = RTA_LENGTH(tabsize);
-
   /* Lock the network so that the Neighbor table will be stable, then
    * copy the Neighbor table into the allocated memory.
    */
 
   net_lock();
   ncopied = neighbor_snapshot(
-    (FAR struct neighbor_entry_s *)entry->payload.data,
-    CONFIG_NET_IPv6_NCONF_ENTRIES);
+                      (FAR struct neighbor_entry_s *)(*entry)->payload.data,
+                      CONFIG_NET_IPv6_NCONF_ENTRIES);
   net_unlock();
 
   /* Now we have the real number of valid entries in the Neighbor table
    * and we can trim the allocation.
    */
 
-  if (ncopied < CONFIG_NET_IPv6_NCONF_ENTRIES)
+  if (ncopied > 0)
     {
       FAR struct getneigh_recvfrom_rsplist_s *newentry;
 
@@ -635,25 +580,147 @@ static int netlink_get_nbtable(NETLINK_HANDLE handle,
       rspsize   = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize);
       allocsize = SIZEOF_NLROUTE_RECVFROM_RSPLIST_S(tabsize);
 
-      newentry = (FAR struct getneigh_recvfrom_rsplist_s *)
-        kmm_realloc(entry, allocsize);
+      newentry = kmm_realloc(*entry, allocsize);
 
       if (newentry != NULL)
         {
-           entry = newentry;
+          *entry = newentry;
         }
 
-      entry->payload.hdr.nlmsg_len = rspsize;
-      entry->payload.attr.rta_len  = RTA_LENGTH(tabsize);
+      (*entry)->payload.hdr.nlmsg_len = rspsize;
+      (*entry)->payload.attr.rta_len  = RTA_LENGTH(tabsize);
     }
 
-  /* Finally, add the response to the list of pending responses */
-
-  netlink_add_response(handle, (FAR struct netlink_response_s *)entry);
-  return OK;
+  return ncopied;
 }
 #endif
 
+/****************************************************************************
+ * Name: netlink_fill_nbtable()
+ *
+ * Description:
+ *   Return the entire IPv6 neighbor table.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_NETLINK_DISABLE_GETNEIGH)
+static FAR struct netlink_response_s *
+netlink_get_neighbor(FAR const void *neigh, int domain, int type,
+                     FAR const struct nlroute_sendto_request_s *req)
+{
+  FAR struct getneigh_recvfrom_rsplist_s *alloc;
+  FAR struct getneigh_recvfrom_response_s *resp;
+  size_t allocsize;
+  size_t tabsize;
+  size_t tabnum;
+  size_t rspsize;
+
+  /* Preallocate memory to hold the maximum sized ARP table
+   * REVISIT:  This is probably excessively large and could cause false
+   * memory out conditions.  A better approach would be to actually count
+   * the number of valid entries in the ARP table.
+   */
+
+#if defined(CONFIG_NET_ARP)
+  if (domain == AF_INET)
+    {
+      tabnum  = req ? CONFIG_NET_ARPTAB_SIZE : 1;
+      tabsize = tabnum * sizeof(struct arpreq);
+    }
+  else
+#endif
+#if defined(CONFIG_NET_IPv6)
+  if (domain == AF_INET6)
+    {
+      tabnum  = req ? CONFIG_NET_IPv6_NCONF_ENTRIES : 1;
+      tabsize = tabnum * sizeof(struct neighbor_entry_s);
+    }
+  else
+#endif
+    {
+      return NULL;
+    }
+
+  rspsize   = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize);
+  allocsize = SIZEOF_NLROUTE_RECVFROM_RSPLIST_S(tabsize);
+
+  /* Allocate the response buffer */
+
+  alloc = kmm_zalloc(allocsize);
+  if (alloc == NULL)
+    {
+      nerr("ERROR: Failed to allocate response buffer.\n");
+      return NULL;
+    }
+
+  /* Initialize the response buffer */
+
+  resp                  = &alloc->payload;
+  resp->hdr.nlmsg_len   = rspsize;
+  resp->hdr.nlmsg_type  = type;
+  resp->hdr.nlmsg_flags = req ? req->hdr.nlmsg_flags : 0;
+  resp->hdr.nlmsg_seq   = req ? req->hdr.nlmsg_seq : 0;
+  resp->hdr.nlmsg_pid   = req ? req->hdr.nlmsg_pid : 0;
+
+  resp->msg.ndm_family = domain;
+  resp->attr.rta_len   = RTA_LENGTH(tabsize);
+
+  /* Copy neigh or arp entries into resp data */
+
+  if (req == NULL)
+    {
+      if (neigh == NULL)
+        {
+          return NULL;
+        }
+
+      /* Only one entry need to notify */
+
+      memcpy(resp->data, neigh, tabsize);
+    }
+#if defined(CONFIG_NET_ARP)
+  else if (domain == AF_INET)
+    {
+      tabnum = netlink_fill_arptable(&alloc);
+    }
+#endif
+#if defined(CONFIG_NET_IPv6)
+  else if (domain == AF_INET6)
+    {
+      tabnum = netlink_fill_nbtable(&alloc);
+    }
+#endif
+
+  /* If no entry in table, just free alloc */
+
+  if (tabnum <= 0)
+    {
+      kmm_free(alloc);
+      nwarn("WARNING: Failed to get entry in %s table.\n",
+            domain == AF_INET ? "ARP" : "neighbor");
+      return NULL;
+    }
+
+  return (FAR struct netlink_response_s *)alloc;
+}
+
+static int netlink_get_neighborlist(NETLINK_HANDLE handle, int domain,
+                              FAR const struct nlroute_sendto_request_s *req)
+{
+  FAR struct netlink_response_s *resp;
+
+  resp = netlink_get_neighbor(NULL, domain, RTM_GETNEIGH, req);
+  if (resp == NULL)
+    {
+      return -ENOENT;
+    }
+
+  netlink_add_response(handle, resp);
+
+  return netlink_add_terminator(handle, &req->hdr, 0);
+}
+#endif /* CONFIG_NETLINK_DISABLE_GETNEIGH */
+
 /****************************************************************************
  * Name: netlink_ipv4_route
  *
@@ -1234,7 +1301,7 @@ ssize_t netlink_route_sendto(NETLINK_HANDLE handle,
 
         if (req->gen.rtgen_family == AF_INET)
           {
-            ret = netlink_get_arptable(handle, req);
+            ret = netlink_get_neighborlist(handle, AF_INET, req);
           }
         else
 #endif
@@ -1244,7 +1311,7 @@ ssize_t netlink_route_sendto(NETLINK_HANDLE handle,
 
         if (req->gen.rtgen_family == AF_INET6)
           {
-             ret = netlink_get_nbtable(handle, req);
+             ret = netlink_get_neighborlist(handle, AF_INET6, req);
           }
         else
 #endif
@@ -1491,4 +1558,28 @@ void netlink_route_notify(FAR const void *route, int 
type, int domain)
 }
 #endif
 
+/****************************************************************************
+ * Name: netlink_neigh_notify()
+ *
+ * Description:
+ *   Perform the neigh broadcast for the NETLINK_ROUTE protocol.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_NETLINK_DISABLE_GETNEIGH
+void netlink_neigh_notify(FAR const void *neigh, int type, int domain)
+{
+  FAR struct netlink_response_s *resp;
+
+  resp = netlink_get_neighbor(neigh, domain, type, NULL);
+  if (resp == NULL)
+    {
+      return;
+    }
+
+  netlink_add_broadcast(RTNLGRP_NEIGH, resp);
+  netlink_add_terminator(NULL, NULL, RTNLGRP_NEIGH);
+}
+#endif
+
 #endif /* CONFIG_NETLINK_ROUTE */

Reply via email to