aboutsummaryrefslogtreecommitdiffstats
path: root/src/neigh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/neigh.c')
-rw-r--r--src/neigh.c853
1 files changed, 0 insertions, 853 deletions
diff --git a/src/neigh.c b/src/neigh.c
deleted file mode 100644
index 799b810..0000000
--- a/src/neigh.c
+++ /dev/null
@@ -1,853 +0,0 @@
-
-#include "config.h"
-#include <net/if_packet.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <netlink/route/rtnl.h>
-#include <netlink/route/link.h>
-#include <netlink/route/route.h>
-#include <netlink/route/neighbour.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/timerfd.h>
-#include <netinet/in.h>
-#include <errno.h>
-#include <unistd.h>
-#include <ifaddrs.h>
-#include <netdb.h>
-#ifndef _LINUX_IF_H
-#include <net/if.h>
-#else
-/*Workaround when there's a collision between the includes */
-extern unsigned int if_nametoindex(__const char *__ifname) __THROW;
-#endif
-
-/* for PFX */
-#include "ibverbs.h"
-
-#include "neigh.h"
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-/* Workaround - declaration missing */
-extern int rtnl_link_vlan_get_id(struct rtnl_link *);
-
-#ifndef HAVE_LIBNL1
-#include <netlink/route/link/vlan.h>
-#endif
-
-static pthread_once_t device_neigh_alloc = PTHREAD_ONCE_INIT;
-static struct nl_sock *zero_socket;
-
-union sktaddr {
- struct sockaddr s;
- struct sockaddr_in s4;
- struct sockaddr_in6 s6;
-};
-
-struct skt {
- union sktaddr sktaddr;
- socklen_t len;
-};
-
-static int set_link_port(union sktaddr *s, int port, int oif)
-{
- switch (s->s.sa_family) {
- case AF_INET:
- s->s4.sin_port = port;
- break;
- case AF_INET6:
- s->s6.sin6_port = port;
- s->s6.sin6_scope_id = oif;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static bool cmp_address(const struct sockaddr *s1,
- const struct sockaddr *s2)
-{
- if (s1->sa_family != s2->sa_family)
- return false;
-
- switch (s1->sa_family) {
- case AF_INET:
- return ((struct sockaddr_in *)s1)->sin_addr.s_addr ==
- ((struct sockaddr_in *)s2)->sin_addr.s_addr;
- case AF_INET6:
- return !memcmp(
- ((struct sockaddr_in6 *)s1)->sin6_addr.s6_addr,
- ((struct sockaddr_in6 *)s2)->sin6_addr.s6_addr,
- sizeof(((struct sockaddr_in6 *)s1)->sin6_addr.s6_addr));
- default:
- return false;
- }
-}
-
-static int get_ifindex(const struct sockaddr *s)
-{
- struct ifaddrs *ifaddr, *ifa;
- int name2index = -ENODEV;
-
- if (-1 == getifaddrs(&ifaddr))
- return errno;
-
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL)
- continue;
-
- if (cmp_address(ifa->ifa_addr, s)) {
- name2index = if_nametoindex(ifa->ifa_name);
- break;
- }
- }
-
- freeifaddrs(ifaddr);
-
- return name2index;
-}
-
-static struct nl_addr *get_neigh_mac(struct get_neigh_handler *neigh_handler)
-{
- struct rtnl_neigh *neigh;
- struct nl_addr *ll_addr = NULL;
-
- /* future optimization - if link local address - parse address and
- * return mac now instead of doing so after the routing CB. This
- * is of course referred to GIDs */
- neigh = rtnl_neigh_get(neigh_handler->neigh_cache,
- neigh_handler->oif,
- neigh_handler->dst);
- if (neigh == NULL)
- return NULL;
-
- ll_addr = rtnl_neigh_get_lladdr(neigh);
- if (NULL != ll_addr)
- ll_addr = nl_addr_clone(ll_addr);
-
- rtnl_neigh_put(neigh);
- return ll_addr;
-}
-
-static void get_neigh_cb_event(struct nl_object *obj, void *arg)
-{
- struct get_neigh_handler *neigh_handler =
- (struct get_neigh_handler *)arg;
- /* assumed serilized callback (no parallel execution of function) */
- if (nl_object_match_filter(
- obj,
- (struct nl_object *)neigh_handler->filter_neigh)) {
- struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
- /* check that we didn't set it already */
- if (neigh_handler->found_ll_addr == NULL) {
- if (rtnl_neigh_get_lladdr(neigh) == NULL)
- return;
-
- neigh_handler->found_ll_addr =
- nl_addr_clone(rtnl_neigh_get_lladdr(neigh));
- }
- }
-}
-
-static int get_neigh_cb(struct nl_msg *msg, void *arg)
-{
- struct get_neigh_handler *neigh_handler =
- (struct get_neigh_handler *)arg;
-
- if (nl_msg_parse(msg, &get_neigh_cb_event, neigh_handler) < 0)
- errno = ENOMSG;
-
- return NL_OK;
-}
-
-static void set_neigh_filter(struct get_neigh_handler *neigh_handler,
- struct rtnl_neigh *filter) {
- neigh_handler->filter_neigh = filter;
-}
-
-static struct rtnl_neigh *create_filter_neigh_for_dst(struct nl_addr *dst_addr,
- int oif)
-{
- struct rtnl_neigh *filter_neigh;
-
- filter_neigh = rtnl_neigh_alloc();
- if (filter_neigh == NULL)
- return NULL;
-
- rtnl_neigh_set_ifindex(filter_neigh, oif);
- rtnl_neigh_set_dst(filter_neigh, dst_addr);
-
- return filter_neigh;
-}
-
-#define PORT_DISCARD htons(9)
-#define SEND_PAYLOAD "H"
-
-static int create_socket(struct get_neigh_handler *neigh_handler,
- struct skt *addr_dst, int *psock_fd)
-{
- int err;
- struct skt addr_src;
- int sock_fd;
-
- memset(addr_dst, 0, sizeof(*addr_dst));
- memset(&addr_src, 0, sizeof(addr_src));
- addr_src.len = sizeof(addr_src.sktaddr);
-
- err = nl_addr_fill_sockaddr(neigh_handler->src,
- &addr_src.sktaddr.s,
- &addr_src.len);
- if (err) {
- errno = EADDRNOTAVAIL;
- return err;
- }
-
- addr_dst->len = sizeof(addr_dst->sktaddr);
- err = nl_addr_fill_sockaddr(neigh_handler->dst,
- &addr_dst->sktaddr.s,
- &addr_dst->len);
- if (err) {
- errno = EADDRNOTAVAIL;
- return err;
- }
-
- err = set_link_port(&addr_dst->sktaddr, PORT_DISCARD,
- neigh_handler->oif);
- if (err)
- return err;
-
- sock_fd = socket(addr_dst->sktaddr.s.sa_family,
- SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sock_fd == -1)
- return errno ? -errno : -1;
- err = bind(sock_fd, &addr_src.sktaddr.s, addr_src.len);
- if (err) {
- int bind_err = -errno;
-
- close(sock_fd);
- return bind_err ?: EADDRNOTAVAIL;
- }
-
- *psock_fd = sock_fd;
-
- return 0;
-}
-
-#define NUM_OF_RETRIES 10
-#define NUM_OF_TRIES ((NUM_OF_RETRIES) + 1)
-#if NUM_OF_TRIES < 1
-#error "neigh: invalid value of NUM_OF_RETRIES"
-#endif
-static int create_timer(struct get_neigh_handler *neigh_handler)
-{
- int user_timeout = neigh_handler->timeout/NUM_OF_TRIES;
- struct timespec timeout = {
- .tv_sec = user_timeout / 1000,
- .tv_nsec = (user_timeout % 1000) * 1000000
- };
- struct itimerspec timer_time = {.it_value = timeout};
- int timer_fd;
-
- timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
- if (timer_fd == -1)
- return timer_fd;
-
- if (neigh_handler->timeout) {
- if (NUM_OF_TRIES <= 1)
- bzero(&timer_time.it_interval,
- sizeof(timer_time.it_interval));
- else
- timer_time.it_interval = timeout;
- if (timerfd_settime(timer_fd, 0, &timer_time, NULL)) {
- close(timer_fd);
- return -1;
- }
- }
-
- return timer_fd;
-}
-
-#define UDP_SOCKET_MAX_SENDTO 100000ULL
-static int try_send_to(int sock_fd, void *buff, size_t buf_size,
- struct skt *addr_dst)
-{
- uint64_t max_count = UDP_SOCKET_MAX_SENDTO;
- int err;
-
- do {
- err = sendto(sock_fd, buff, buf_size, 0,
- &addr_dst->sktaddr.s,
- addr_dst->len);
- if (err > 0)
- err = 0;
- } while (-1 == err && EADDRNOTAVAIL == errno && --max_count);
-
- return err;
-}
-
-static struct nl_addr *process_get_neigh_mac(
- struct get_neigh_handler *neigh_handler)
-{
- int err;
- struct nl_addr *ll_addr = get_neigh_mac(neigh_handler);
- struct rtnl_neigh *neigh_filter;
- fd_set fdset;
- int sock_fd;
- int fd;
- int nfds;
- int timer_fd;
- int ret;
- struct skt addr_dst;
- char buff[sizeof(SEND_PAYLOAD)] = SEND_PAYLOAD;
- int retries = 0;
-
- if (NULL != ll_addr)
- return ll_addr;
-
- err = nl_socket_add_membership(neigh_handler->sock,
- RTNLGRP_NEIGH);
- if (err < 0)
- return NULL;
-
- neigh_filter = create_filter_neigh_for_dst(neigh_handler->dst,
- neigh_handler->oif);
- if (neigh_filter == NULL)
- return NULL;
-
- set_neigh_filter(neigh_handler, neigh_filter);
-
- nl_socket_disable_seq_check(neigh_handler->sock);
- nl_socket_modify_cb(neigh_handler->sock, NL_CB_VALID, NL_CB_CUSTOM,
- &get_neigh_cb, neigh_handler);
-
- fd = nl_socket_get_fd(neigh_handler->sock);
-
- err = create_socket(neigh_handler, &addr_dst, &sock_fd);
-
- if (err)
- return NULL;
-
- err = try_send_to(sock_fd, buff, sizeof(buff), &addr_dst);
- if (err)
- goto close_socket;
-
- timer_fd = create_timer(neigh_handler);
- if (timer_fd < 0)
- goto close_socket;
-
- nfds = MAX(fd, timer_fd) + 1;
-
- while (1) {
- FD_ZERO(&fdset);
- FD_SET(fd, &fdset);
- FD_SET(timer_fd, &fdset);
-
- /* wait for an incoming message on the netlink socket */
- ret = select(nfds, &fdset, NULL, NULL, NULL);
- if (ret == -1) {
- goto select_err;
- } else if (ret) {
- if (FD_ISSET(fd, &fdset)) {
- nl_recvmsgs_default(neigh_handler->sock);
- if (neigh_handler->found_ll_addr)
- break;
- } else {
- nl_cache_refill(neigh_handler->sock,
- neigh_handler->neigh_cache);
- ll_addr = get_neigh_mac(neigh_handler);
- if (NULL != ll_addr) {
- break;
- } else if (FD_ISSET(timer_fd, &fdset) &&
- retries < NUM_OF_RETRIES) {
- try_send_to(sock_fd, buff, sizeof(buff),
- &addr_dst);
- }
- }
-
- if (FD_ISSET(timer_fd, &fdset)) {
- uint64_t read_val;
-
- (void)read(timer_fd, &read_val,
- sizeof(read_val));
- if (++retries >= NUM_OF_TRIES) {
- if (!errno)
- errno = EDESTADDRREQ;
- break;
- }
- }
- }
- }
-select_err:
- close(timer_fd);
-close_socket:
- close(sock_fd);
- return ll_addr ? ll_addr : neigh_handler->found_ll_addr;
-}
-
-static int get_mcast_mac_ipv4(struct nl_addr *dst, struct nl_addr **ll_addr)
-{
- uint8_t mac_addr[6] = {0x01, 0x00, 0x5E};
- uint32_t addr = ntohl(*(uint32_t *)nl_addr_get_binary_addr(dst));
-
- mac_addr[5] = addr & 0xFF;
- addr >>= 8;
- mac_addr[4] = addr & 0xFF;
- addr >>= 8;
- mac_addr[3] = addr & 0x7F;
-
- *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
-
- return *ll_addr == NULL ? -EINVAL : 0;
-}
-
-static int get_mcast_mac_ipv6(struct nl_addr *dst, struct nl_addr **ll_addr)
-{
- uint8_t mac_addr[6] = {0x33, 0x33};
-
- memcpy(mac_addr + 2, (uint8_t *)nl_addr_get_binary_addr(dst) + 12, 4);
-
- *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
-
- return *ll_addr == NULL ? -EINVAL : 0;
-}
-
-static int get_link_local_mac_ipv6(struct nl_addr *dst,
- struct nl_addr **ll_addr)
-{
- uint8_t mac_addr[6];
-
- memcpy(mac_addr + 3, (uint8_t *)nl_addr_get_binary_addr(dst) + 13, 3);
- memcpy(mac_addr, (uint8_t *)nl_addr_get_binary_addr(dst) + 8, 3);
- mac_addr[0] ^= 2;
-
- *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
- return *ll_addr == NULL ? -EINVAL : 0;
-}
-
-static const struct encoded_l3_addr {
- short family;
- uint8_t prefix_bits;
- const uint8_t data[16];
- int (*getter)(struct nl_addr *dst, struct nl_addr **ll_addr);
-} encoded_prefixes[] = {
- {.family = AF_INET,
- .prefix_bits = 4,
- .data = {0xe0},
- .getter = &get_mcast_mac_ipv4},
- {.family = AF_INET6,
- .prefix_bits = 8,
- .data = {0xff},
- .getter = &get_mcast_mac_ipv6},
- {.family = AF_INET6,
- .prefix_bits = 64,
- .data = {0xfe, 0x80},
- .getter = get_link_local_mac_ipv6},
-};
-
-static int nl_addr_cmp_prefix_msb(void *addr1, int len1, void *addr2, int len2)
-{
- int len = MIN(len1, len2);
- int bytes = len / 8;
- int d = memcmp(addr1, addr2, bytes);
-
- if (d == 0) {
- int mask = ((1UL << (len % 8)) - 1UL) << (8 - len);
-
- d = (((uint8_t *)addr1)[bytes] & mask) -
- (((uint8_t *)addr2)[bytes] & mask);
- }
-
- return d;
-}
-
-static int handle_encoded_mac(struct nl_addr *dst, struct nl_addr **ll_addr)
-{
- uint32_t family = nl_addr_get_family(dst);
- struct nl_addr *prefix = NULL;
- int i;
- int ret = 1;
-
- for (i = 0;
- i < sizeof(encoded_prefixes)/sizeof(encoded_prefixes[0]) &&
- ret; prefix = NULL, i++) {
- if (encoded_prefixes[i].family != family)
- continue;
-
- prefix = nl_addr_build(
- family,
- (void *)encoded_prefixes[i].data,
- MIN(encoded_prefixes[i].prefix_bits/8 +
- !!(encoded_prefixes[i].prefix_bits % 8),
- sizeof(encoded_prefixes[i].data)));
-
- if (prefix == NULL)
- return -ENOMEM;
- nl_addr_set_prefixlen(prefix,
- encoded_prefixes[i].prefix_bits);
-
- if (nl_addr_cmp_prefix_msb(nl_addr_get_binary_addr(dst),
- nl_addr_get_prefixlen(dst),
- nl_addr_get_binary_addr(prefix),
- nl_addr_get_prefixlen(prefix)))
- continue;
-
- ret = encoded_prefixes[i].getter(dst, ll_addr);
- nl_addr_put(prefix);
- }
-
- return ret;
-}
-
-static void get_route_cb_parser(struct nl_object *obj, void *arg)
-{
- struct get_neigh_handler *neigh_handler =
- (struct get_neigh_handler *)arg;
-
- struct rtnl_route *route = (struct rtnl_route *)obj;
- struct nl_addr *gateway = NULL;
- struct nl_addr *src = rtnl_route_get_pref_src(route);
- int oif;
- int type = rtnl_route_get_type(route);
- struct rtnl_link *link;
-
- struct rtnl_nexthop *nh = rtnl_route_nexthop_n(route, 0);
-
- if (nh != NULL)
- gateway = rtnl_route_nh_get_gateway(nh);
- oif = rtnl_route_nh_get_ifindex(nh);
-
- if (gateway) {
- nl_addr_put(neigh_handler->dst);
- neigh_handler->dst = nl_addr_clone(gateway);
- }
-
- if (RTN_BLACKHOLE == type ||
- RTN_UNREACHABLE == type ||
- RTN_PROHIBIT == type ||
- RTN_THROW == type) {
- errno = ENETUNREACH;
- goto err;
- }
-
- if (!neigh_handler->src && src)
- neigh_handler->src = nl_addr_clone(src);
-
- if (neigh_handler->oif < 0 && oif > 0)
- neigh_handler->oif = oif;
-
- /* Link Local */
- if (RTN_LOCAL == type) {
- struct nl_addr *lladdr;
-
- link = rtnl_link_get(neigh_handler->link_cache,
- neigh_handler->oif);
-
- if (link == NULL)
- goto err;
-
- lladdr = rtnl_link_get_addr(link);
-
- if (lladdr == NULL)
- goto err_link;
-
- neigh_handler->found_ll_addr = nl_addr_clone(lladdr);
- rtnl_link_put(link);
- } else {
- handle_encoded_mac(
- neigh_handler->dst,
- &neigh_handler->found_ll_addr);
- }
-
- return;
-
-err_link:
- rtnl_link_put(link);
-err:
- if (neigh_handler->src) {
- nl_addr_put(neigh_handler->src);
- neigh_handler->src = NULL;
- }
-}
-
-static int get_route_cb(struct nl_msg *msg, void *arg)
-{
- struct get_neigh_handler *neigh_handler =
- (struct get_neigh_handler *)arg;
- int err;
-
- err = nl_msg_parse(msg, &get_route_cb_parser, neigh_handler);
- if (err < 0) {
- errno = ENOMSG;
- return err;
- }
-
- if (!neigh_handler->dst || !neigh_handler->src ||
- neigh_handler->oif <= 0) {
- errno = EINVAL;
- return -1;
- }
-
- if (NULL != neigh_handler->found_ll_addr)
- goto found;
-
- neigh_handler->found_ll_addr =
- process_get_neigh_mac(neigh_handler);
-
-found:
- return neigh_handler->found_ll_addr ? 0 : -1;
-}
-
-int neigh_get_oif_from_src(struct get_neigh_handler *neigh_handler)
-{
- int oif = -ENODEV;
- struct addrinfo *src_info;
- int err;
-
- err = nl_addr_info(neigh_handler->src, &src_info);
- if (err) {
- if (!errno)
- errno = ENXIO;
- return oif;
- }
-
- oif = get_ifindex(src_info->ai_addr);
- if (oif <= 0)
- goto free;
-
-free:
- freeaddrinfo(src_info);
- return oif;
-}
-
-static void destroy_zero_based_socket(void)
-{
- if (zero_socket != NULL)
- nl_socket_free(zero_socket);
-}
-
-static void alloc_zero_based_socket(void)
-{
- zero_socket = nl_socket_alloc();
- atexit(&destroy_zero_based_socket);
-}
-
-int neigh_init_resources(struct get_neigh_handler *neigh_handler, int timeout)
-{
- int err;
-
- pthread_once(&device_neigh_alloc, &alloc_zero_based_socket);
- neigh_handler->sock = nl_socket_alloc();
- if (neigh_handler->sock == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- err = nl_connect(neigh_handler->sock, NETLINK_ROUTE);
- if (err < 0)
- goto free_socket;
-
- err = rtnl_link_alloc_cache(neigh_handler->sock, AF_UNSPEC,
- &neigh_handler->link_cache);
- if (err) {
- err = -1;
- errno = ENOMEM;
- goto close_connection;
- }
-
- nl_cache_mngt_provide(neigh_handler->link_cache);
-
- err = rtnl_route_alloc_cache(neigh_handler->sock, AF_UNSPEC, 0,
- &neigh_handler->route_cache);
- if (err) {
- err = -1;
- errno = ENOMEM;
- goto free_link_cache;
- }
-
- nl_cache_mngt_provide(neigh_handler->route_cache);
-
- err = rtnl_neigh_alloc_cache(neigh_handler->sock,
- &neigh_handler->neigh_cache);
- if (err) {
- err = -ENOMEM;
- goto free_route_cache;
- }
-
- nl_cache_mngt_provide(neigh_handler->neigh_cache);
-
- /* init structure */
- neigh_handler->timeout = timeout;
- neigh_handler->oif = -1;
- neigh_handler->filter_neigh = NULL;
- neigh_handler->found_ll_addr = NULL;
- neigh_handler->dst = NULL;
- neigh_handler->src = NULL;
- neigh_handler->vid = -1;
-
- return 0;
-
-free_route_cache:
- nl_cache_mngt_unprovide(neigh_handler->route_cache);
- nl_cache_free(neigh_handler->route_cache);
- neigh_handler->route_cache = NULL;
-free_link_cache:
- nl_cache_mngt_unprovide(neigh_handler->link_cache);
- nl_cache_free(neigh_handler->link_cache);
- neigh_handler->link_cache = NULL;
-close_connection:
- nl_close(neigh_handler->sock);
-free_socket:
- nl_socket_free(neigh_handler->sock);
- neigh_handler->sock = NULL;
- return err;
-}
-
-uint16_t neigh_get_vlan_id_from_dev(struct get_neigh_handler *neigh_handler)
-{
- struct rtnl_link *link;
- int vid = 0xffff;
-
- link = rtnl_link_get(neigh_handler->link_cache, neigh_handler->oif);
- if (link == NULL) {
- errno = EINVAL;
- return vid;
- }
-
- if (rtnl_link_is_vlan(link))
- vid = rtnl_link_vlan_get_id(link);
- rtnl_link_put(link);
- return vid >= 0 && vid <= 0xfff ? vid : 0xffff;
-}
-
-void neigh_set_vlan_id(struct get_neigh_handler *neigh_handler, uint16_t vid)
-{
- if (vid >= 0 && vid <= 0xfff)
- neigh_handler->vid = vid;
-}
-
-int neigh_set_dst(struct get_neigh_handler *neigh_handler,
- int family, void *buf, size_t size)
-{
- neigh_handler->dst = nl_addr_build(family, buf, size);
- return neigh_handler->dst == NULL;
-}
-
-int neigh_set_src(struct get_neigh_handler *neigh_handler,
- int family, void *buf, size_t size)
-{
- neigh_handler->src = nl_addr_build(family, buf, size);
- return neigh_handler->src == NULL;
-}
-
-void neigh_set_oif(struct get_neigh_handler *neigh_handler, int oif)
-{
- neigh_handler->oif = oif;
-}
-
-int neigh_get_ll(struct get_neigh_handler *neigh_handler, void *addr_buff,
- int addr_size) {
- int neigh_len;
-
- if (neigh_handler->found_ll_addr == NULL)
- return -EINVAL;
-
- neigh_len = nl_addr_get_len(neigh_handler->found_ll_addr);
-
- if (neigh_len > addr_size)
- return -EINVAL;
-
- memcpy(addr_buff, nl_addr_get_binary_addr(neigh_handler->found_ll_addr),
- neigh_len);
-
- return neigh_len;
-}
-
-void neigh_free_resources(struct get_neigh_handler *neigh_handler)
-{
- /* Should be released first because it's holding a reference to dst */
- if (neigh_handler->filter_neigh != NULL) {
- rtnl_neigh_put(neigh_handler->filter_neigh);
- neigh_handler->filter_neigh = NULL;
- }
-
- if (neigh_handler->src != NULL) {
- nl_addr_put(neigh_handler->src);
- neigh_handler->src = NULL;
- }
-
- if (neigh_handler->dst != NULL) {
- nl_addr_put(neigh_handler->dst);
- neigh_handler->dst = NULL;
- }
-
- if (neigh_handler->found_ll_addr != NULL) {
- nl_addr_put(neigh_handler->found_ll_addr);
- neigh_handler->found_ll_addr = NULL;
- }
-
- if (neigh_handler->neigh_cache != NULL) {
- nl_cache_mngt_unprovide(neigh_handler->neigh_cache);
- nl_cache_free(neigh_handler->neigh_cache);
- neigh_handler->neigh_cache = NULL;
- }
-
- if (neigh_handler->route_cache != NULL) {
- nl_cache_mngt_unprovide(neigh_handler->route_cache);
- nl_cache_free(neigh_handler->route_cache);
- neigh_handler->route_cache = NULL;
- }
-
- if (neigh_handler->link_cache != NULL) {
- nl_cache_mngt_unprovide(neigh_handler->link_cache);
- nl_cache_free(neigh_handler->link_cache);
- neigh_handler->link_cache = NULL;
- }
-
- if (neigh_handler->sock != NULL) {
- nl_close(neigh_handler->sock);
- nl_socket_free(neigh_handler->sock);
- neigh_handler->sock = NULL;
- }
-}
-
-int process_get_neigh(struct get_neigh_handler *neigh_handler)
-{
- struct nl_msg *m;
- struct rtmsg rmsg = {
- .rtm_family = nl_addr_get_family(neigh_handler->dst),
- .rtm_dst_len = nl_addr_get_prefixlen(neigh_handler->dst),
- };
- int err;
-
- m = nlmsg_alloc_simple(RTM_GETROUTE, 0);
-
- if (m == NULL)
- return -ENOMEM;
-
- nlmsg_append(m, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
-
- nla_put_addr(m, RTA_DST, neigh_handler->dst);
-
- if (neigh_handler->oif > 0)
- nla_put_u32(m, RTA_OIF, neigh_handler->oif);
-
- err = nl_send_auto_complete(neigh_handler->sock, m);
- nlmsg_free(m);
- if (err < 0)
- return err;
-
- nl_socket_modify_cb(neigh_handler->sock, NL_CB_VALID,
- NL_CB_CUSTOM, &get_route_cb, neigh_handler);
-
- err = nl_recvmsgs_default(neigh_handler->sock);
-
- return err;
-}