neigh.c revision 331769
1/* Licensed under the OpenIB.org BSD license (FreeBSD Variant) - See COPYING.md
2 */
3
4#include "config.h"
5#include <net/if_packet.h>
6#include <linux/netlink.h>
7#include <linux/rtnetlink.h>
8#include <infiniband/endian.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdbool.h>
12
13#if HAVE_WORKING_IF_H
14#include <net/if.h>
15#endif
16
17#include <netlink/route/rtnl.h>
18#include <netlink/route/link.h>
19#include <netlink/route/route.h>
20#include <netlink/route/neighbour.h>
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/timerfd.h>
25#include <errno.h>
26#include <unistd.h>
27#include <ifaddrs.h>
28#include <netdb.h>
29#include <assert.h>
30
31#if !HAVE_WORKING_IF_H
32/* We need this decl from net/if.h but old systems do not let use co-include
33   net/if.h and netlink/route/link.h */
34extern unsigned int if_nametoindex(__const char *__ifname) __THROW;
35#endif
36
37/* for PFX */
38#include "ibverbs.h"
39#include <sys/param.h>
40
41#include "neigh.h"
42
43#ifndef HAVE_LIBNL1
44#include <netlink/route/link/vlan.h>
45#endif
46
47static pthread_once_t device_neigh_alloc = PTHREAD_ONCE_INIT;
48static struct nl_sock *zero_socket;
49
50union sktaddr {
51	struct sockaddr s;
52	struct sockaddr_in s4;
53	struct sockaddr_in6 s6;
54};
55
56struct skt {
57	union sktaddr sktaddr;
58	socklen_t len;
59};
60
61static int set_link_port(union sktaddr *s, __be16 port, int oif)
62{
63	switch (s->s.sa_family) {
64	case AF_INET:
65		s->s4.sin_port = port;
66		break;
67	case AF_INET6:
68		s->s6.sin6_port = port;
69		s->s6.sin6_scope_id = oif;
70		break;
71	default:
72		return -EINVAL;
73	}
74
75	return 0;
76}
77
78static bool cmp_address(const struct sockaddr *s1,
79			const struct sockaddr *s2)
80{
81	if (s1->sa_family != s2->sa_family)
82		return false;
83
84	switch (s1->sa_family) {
85	case AF_INET:
86		return ((struct sockaddr_in *)s1)->sin_addr.s_addr ==
87		       ((struct sockaddr_in *)s2)->sin_addr.s_addr;
88	case AF_INET6:
89		return !memcmp(
90			((struct sockaddr_in6 *)s1)->sin6_addr.s6_addr,
91			((struct sockaddr_in6 *)s2)->sin6_addr.s6_addr,
92			sizeof(((struct sockaddr_in6 *)s1)->sin6_addr.s6_addr));
93	default:
94		return false;
95	}
96}
97
98static int get_ifindex(const struct sockaddr *s)
99{
100	struct ifaddrs *ifaddr, *ifa;
101	int name2index = -ENODEV;
102
103	if (-1 == getifaddrs(&ifaddr))
104		return errno;
105
106	for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
107		if (ifa->ifa_addr == NULL)
108			continue;
109
110		if (cmp_address(ifa->ifa_addr, s)) {
111			name2index = if_nametoindex(ifa->ifa_name);
112			break;
113		}
114	}
115
116	freeifaddrs(ifaddr);
117
118	return name2index;
119}
120
121static struct nl_addr *get_neigh_mac(struct get_neigh_handler *neigh_handler)
122{
123	struct rtnl_neigh *neigh;
124	struct nl_addr *ll_addr = NULL;
125
126	/* future optimization - if link local address - parse address and
127	 * return mac now instead of doing so after the routing CB. This
128	 * is of course referred to GIDs */
129	neigh = rtnl_neigh_get(neigh_handler->neigh_cache,
130			       neigh_handler->oif,
131			       neigh_handler->dst);
132	if (neigh == NULL)
133		return NULL;
134
135	ll_addr = rtnl_neigh_get_lladdr(neigh);
136	if (NULL != ll_addr)
137		ll_addr = nl_addr_clone(ll_addr);
138
139	rtnl_neigh_put(neigh);
140	return ll_addr;
141}
142
143static void get_neigh_cb_event(struct nl_object *obj, void *arg)
144{
145	struct get_neigh_handler *neigh_handler =
146		(struct get_neigh_handler *)arg;
147	/* assumed serilized callback (no parallel execution of function) */
148	if (nl_object_match_filter(
149		obj,
150		(struct nl_object *)neigh_handler->filter_neigh)) {
151		struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
152		/* check that we didn't set it already */
153		if (neigh_handler->found_ll_addr == NULL) {
154			if (rtnl_neigh_get_lladdr(neigh) == NULL)
155				return;
156
157			neigh_handler->found_ll_addr =
158				nl_addr_clone(rtnl_neigh_get_lladdr(neigh));
159		}
160	}
161}
162
163static int get_neigh_cb(struct nl_msg *msg, void *arg)
164{
165	struct get_neigh_handler *neigh_handler =
166		(struct get_neigh_handler *)arg;
167
168	if (nl_msg_parse(msg, &get_neigh_cb_event, neigh_handler) < 0)
169		errno = ENOMSG;
170
171	return NL_OK;
172}
173
174static void set_neigh_filter(struct get_neigh_handler *neigh_handler,
175			     struct rtnl_neigh *filter) {
176	neigh_handler->filter_neigh = filter;
177}
178
179static struct rtnl_neigh *create_filter_neigh_for_dst(struct nl_addr *dst_addr,
180						      int oif)
181{
182	struct rtnl_neigh *filter_neigh;
183
184	filter_neigh = rtnl_neigh_alloc();
185	if (filter_neigh == NULL)
186		return NULL;
187
188	rtnl_neigh_set_ifindex(filter_neigh, oif);
189	rtnl_neigh_set_dst(filter_neigh, dst_addr);
190
191	return filter_neigh;
192}
193
194#define PORT_DISCARD htobe16(9)
195#define SEND_PAYLOAD "H"
196
197static int create_socket(struct get_neigh_handler *neigh_handler,
198			 struct skt *addr_dst, int *psock_fd)
199{
200	int err;
201	struct skt addr_src;
202	int sock_fd;
203
204	memset(addr_dst, 0, sizeof(*addr_dst));
205	memset(&addr_src, 0, sizeof(addr_src));
206	addr_src.len = sizeof(addr_src.sktaddr);
207
208	err = nl_addr_fill_sockaddr(neigh_handler->src,
209				    &addr_src.sktaddr.s,
210				    &addr_src.len);
211	if (err) {
212		errno = EADDRNOTAVAIL;
213		return -1;
214	}
215
216	addr_dst->len = sizeof(addr_dst->sktaddr);
217	err = nl_addr_fill_sockaddr(neigh_handler->dst,
218				    &addr_dst->sktaddr.s,
219				    &addr_dst->len);
220	if (err) {
221		errno = EADDRNOTAVAIL;
222		return -1;
223	}
224
225	err = set_link_port(&addr_dst->sktaddr, PORT_DISCARD,
226			    neigh_handler->oif);
227	if (err)
228		return -1;
229
230	sock_fd = socket(addr_dst->sktaddr.s.sa_family,
231			 SOCK_DGRAM | SOCK_CLOEXEC, 0);
232	if (sock_fd == -1)
233		return -1;
234	err = bind(sock_fd, &addr_src.sktaddr.s, addr_src.len);
235	if (err) {
236		close(sock_fd);
237		return -1;
238	}
239
240	*psock_fd = sock_fd;
241
242	return 0;
243}
244
245#define NUM_OF_RETRIES 10
246#define NUM_OF_TRIES ((NUM_OF_RETRIES) + 1)
247#if NUM_OF_TRIES < 1
248#error "neigh: invalid value of NUM_OF_RETRIES"
249#endif
250static int create_timer(struct get_neigh_handler *neigh_handler)
251{
252	int user_timeout = neigh_handler->timeout/NUM_OF_TRIES;
253	struct timespec timeout = {
254		.tv_sec = user_timeout / 1000,
255		.tv_nsec = (user_timeout % 1000) * 1000000
256	};
257	struct itimerspec timer_time = {.it_value = timeout};
258	int timer_fd;
259
260	timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
261	if (timer_fd == -1)
262		return timer_fd;
263
264	if (neigh_handler->timeout) {
265		if (NUM_OF_TRIES <= 1)
266			bzero(&timer_time.it_interval,
267			      sizeof(timer_time.it_interval));
268		else
269			timer_time.it_interval = timeout;
270		if (timerfd_settime(timer_fd, 0, &timer_time, NULL)) {
271			close(timer_fd);
272			return -1;
273		}
274	}
275
276	return timer_fd;
277}
278
279#define UDP_SOCKET_MAX_SENDTO 100000ULL
280static int try_send_to(int sock_fd, void *buff, size_t buf_size,
281		       struct skt *addr_dst)
282{
283	uint64_t max_count = UDP_SOCKET_MAX_SENDTO;
284	int err;
285
286	do {
287		err = sendto(sock_fd, buff, buf_size, 0,
288			     &addr_dst->sktaddr.s,
289			     addr_dst->len);
290		if (err > 0)
291			err = 0;
292	} while (-1 == err && EADDRNOTAVAIL == errno && --max_count);
293
294	return err;
295}
296
297static struct nl_addr *process_get_neigh_mac(
298		struct get_neigh_handler *neigh_handler)
299{
300	int err;
301	struct nl_addr *ll_addr = get_neigh_mac(neigh_handler);
302	struct rtnl_neigh *neigh_filter;
303	fd_set fdset;
304	int sock_fd;
305	int fd;
306	int nfds;
307	int timer_fd;
308	int ret;
309	struct skt addr_dst;
310	char buff[sizeof(SEND_PAYLOAD)] = SEND_PAYLOAD;
311	int retries = 0;
312
313	if (NULL != ll_addr)
314		return ll_addr;
315
316	err = nl_socket_add_membership(neigh_handler->sock,
317				       RTNLGRP_NEIGH);
318	if (err < 0)
319		return NULL;
320
321	neigh_filter = create_filter_neigh_for_dst(neigh_handler->dst,
322						   neigh_handler->oif);
323	if (neigh_filter == NULL)
324		return NULL;
325
326	set_neigh_filter(neigh_handler, neigh_filter);
327
328	nl_socket_disable_seq_check(neigh_handler->sock);
329	nl_socket_modify_cb(neigh_handler->sock, NL_CB_VALID, NL_CB_CUSTOM,
330			    &get_neigh_cb, neigh_handler);
331
332	fd = nl_socket_get_fd(neigh_handler->sock);
333
334	err = create_socket(neigh_handler, &addr_dst, &sock_fd);
335
336	if (err)
337		return NULL;
338
339	err = try_send_to(sock_fd, buff, sizeof(buff), &addr_dst);
340	if (err)
341		goto close_socket;
342
343	timer_fd = create_timer(neigh_handler);
344	if (timer_fd < 0)
345		goto close_socket;
346
347	nfds = MAX(fd, timer_fd) + 1;
348
349	while (1) {
350		FD_ZERO(&fdset);
351		FD_SET(fd, &fdset);
352		FD_SET(timer_fd, &fdset);
353
354		/* wait for an incoming message on the netlink socket */
355		ret = select(nfds, &fdset, NULL, NULL, NULL);
356		if (ret == -1) {
357			goto select_err;
358		} else if (ret) {
359			if (FD_ISSET(fd, &fdset)) {
360				nl_recvmsgs_default(neigh_handler->sock);
361				if (neigh_handler->found_ll_addr)
362					break;
363			} else {
364				nl_cache_refill(neigh_handler->sock,
365						neigh_handler->neigh_cache);
366				ll_addr = get_neigh_mac(neigh_handler);
367				if (NULL != ll_addr) {
368					break;
369				} else if (FD_ISSET(timer_fd, &fdset) &&
370					   retries < NUM_OF_RETRIES) {
371					try_send_to(sock_fd, buff, sizeof(buff),
372						    &addr_dst);
373				}
374			}
375
376			if (FD_ISSET(timer_fd, &fdset)) {
377				uint64_t read_val;
378				ssize_t rc;
379
380				rc =
381				    read(timer_fd, &read_val, sizeof(read_val));
382				assert(rc == sizeof(read_val));
383				if (++retries >=  NUM_OF_TRIES) {
384					if (!errno)
385						errno = EDESTADDRREQ;
386					break;
387				}
388			}
389		}
390	}
391select_err:
392	close(timer_fd);
393close_socket:
394	close(sock_fd);
395	return ll_addr ? ll_addr : neigh_handler->found_ll_addr;
396}
397
398static int get_mcast_mac_ipv4(struct nl_addr *dst, struct nl_addr **ll_addr)
399{
400	uint8_t mac_addr[6] = {0x01, 0x00, 0x5E};
401	uint32_t addr = be32toh(*(__be32 *)nl_addr_get_binary_addr(dst));
402
403	mac_addr[5] = addr & 0xFF;
404	addr >>= 8;
405	mac_addr[4] = addr & 0xFF;
406	addr >>= 8;
407	mac_addr[3] = addr & 0x7F;
408
409	*ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
410
411	return *ll_addr == NULL ? -EINVAL : 0;
412}
413
414static int get_mcast_mac_ipv6(struct nl_addr *dst, struct nl_addr **ll_addr)
415{
416	uint8_t mac_addr[6] = {0x33, 0x33};
417
418	memcpy(mac_addr + 2, (uint8_t *)nl_addr_get_binary_addr(dst) + 12, 4);
419
420	*ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
421
422	return *ll_addr == NULL ? -EINVAL : 0;
423}
424
425static int get_link_local_mac_ipv6(struct nl_addr *dst,
426				   struct nl_addr **ll_addr)
427{
428	uint8_t mac_addr[6];
429
430	memcpy(mac_addr + 3, (uint8_t *)nl_addr_get_binary_addr(dst) + 13, 3);
431	memcpy(mac_addr, (uint8_t *)nl_addr_get_binary_addr(dst) + 8, 3);
432	mac_addr[0] ^= 2;
433
434	*ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr));
435	return *ll_addr == NULL ? -EINVAL : 0;
436}
437
438static const struct encoded_l3_addr {
439	short family;
440	uint8_t prefix_bits;
441	const uint8_t data[16];
442	int (*getter)(struct nl_addr *dst, struct nl_addr **ll_addr);
443} encoded_prefixes[] = {
444	{.family = AF_INET,
445	 .prefix_bits = 4,
446	 .data = {0xe0},
447	 .getter = &get_mcast_mac_ipv4},
448	{.family = AF_INET6,
449	 .prefix_bits = 8,
450	 .data = {0xff},
451	 .getter = &get_mcast_mac_ipv6},
452	{.family = AF_INET6,
453	 .prefix_bits = 64,
454	 .data = {0xfe, 0x80},
455	 .getter = get_link_local_mac_ipv6},
456};
457
458static int nl_addr_cmp_prefix_msb(void *addr1, int len1, void *addr2, int len2)
459{
460	int len = min(len1, len2);
461	int bytes = len / 8;
462	int d = memcmp(addr1, addr2, bytes);
463
464	if (d == 0) {
465		int mask = ((1UL << (len % 8)) - 1UL) << (8 - len);
466
467		d = (((uint8_t *)addr1)[bytes] & mask) -
468		    (((uint8_t *)addr2)[bytes] & mask);
469	}
470
471	return d;
472}
473
474static int handle_encoded_mac(struct nl_addr *dst, struct nl_addr **ll_addr)
475{
476	uint32_t family = nl_addr_get_family(dst);
477	struct nl_addr *prefix = NULL;
478	int i;
479	int ret = 1;
480
481	for (i = 0;
482	     i < sizeof(encoded_prefixes)/sizeof(encoded_prefixes[0]) &&
483	     ret; prefix = NULL, i++) {
484		if (encoded_prefixes[i].family != family)
485			continue;
486
487		prefix = nl_addr_build(
488		    family, (void *)encoded_prefixes[i].data,
489		    min_t(size_t, encoded_prefixes[i].prefix_bits / 8 +
490				      !!(encoded_prefixes[i].prefix_bits % 8),
491			  sizeof(encoded_prefixes[i].data)));
492
493		if (prefix == NULL)
494			return -ENOMEM;
495		nl_addr_set_prefixlen(prefix,
496				      encoded_prefixes[i].prefix_bits);
497
498		if (nl_addr_cmp_prefix_msb(nl_addr_get_binary_addr(dst),
499					   nl_addr_get_prefixlen(dst),
500					   nl_addr_get_binary_addr(prefix),
501					   nl_addr_get_prefixlen(prefix)))
502			continue;
503
504		ret = encoded_prefixes[i].getter(dst, ll_addr);
505		nl_addr_put(prefix);
506	}
507
508	return ret;
509}
510
511static void get_route_cb_parser(struct nl_object *obj, void *arg)
512{
513	struct get_neigh_handler *neigh_handler =
514		(struct get_neigh_handler *)arg;
515
516	struct rtnl_route *route = (struct rtnl_route *)obj;
517	struct nl_addr *gateway = NULL;
518	struct nl_addr *src = rtnl_route_get_pref_src(route);
519	int oif;
520	int type = rtnl_route_get_type(route);
521	struct rtnl_link *link;
522
523	struct rtnl_nexthop *nh = rtnl_route_nexthop_n(route, 0);
524
525	if (nh != NULL)
526		gateway = rtnl_route_nh_get_gateway(nh);
527	oif = rtnl_route_nh_get_ifindex(nh);
528
529	if (gateway) {
530		nl_addr_put(neigh_handler->dst);
531		neigh_handler->dst = nl_addr_clone(gateway);
532	}
533
534	if (RTN_BLACKHOLE == type ||
535	    RTN_UNREACHABLE == type ||
536	    RTN_PROHIBIT == type ||
537	    RTN_THROW == type) {
538		errno = ENETUNREACH;
539		goto err;
540	}
541
542	if (!neigh_handler->src && src)
543		neigh_handler->src = nl_addr_clone(src);
544
545	if (neigh_handler->oif < 0 && oif > 0)
546		neigh_handler->oif = oif;
547
548	/* Link Local */
549	if (RTN_LOCAL == type) {
550		struct nl_addr *lladdr;
551
552		link = rtnl_link_get(neigh_handler->link_cache,
553				     neigh_handler->oif);
554
555		if (link == NULL)
556			goto err;
557
558		lladdr = rtnl_link_get_addr(link);
559
560		if (lladdr == NULL)
561			goto err_link;
562
563		neigh_handler->found_ll_addr = nl_addr_clone(lladdr);
564		rtnl_link_put(link);
565	} else {
566		handle_encoded_mac(
567			neigh_handler->dst,
568			&neigh_handler->found_ll_addr);
569	}
570
571	return;
572
573err_link:
574	rtnl_link_put(link);
575err:
576	if (neigh_handler->src) {
577		nl_addr_put(neigh_handler->src);
578		neigh_handler->src = NULL;
579	}
580}
581
582static int get_route_cb(struct nl_msg *msg, void *arg)
583{
584	struct get_neigh_handler *neigh_handler =
585		(struct get_neigh_handler *)arg;
586	int err;
587
588	err = nl_msg_parse(msg, &get_route_cb_parser, neigh_handler);
589	if (err < 0) {
590		errno = ENOMSG;
591		return err;
592	}
593
594	if (!neigh_handler->dst || !neigh_handler->src ||
595	    neigh_handler->oif <= 0) {
596		errno = EINVAL;
597		return -1;
598	}
599
600	if (NULL != neigh_handler->found_ll_addr)
601		goto found;
602
603	neigh_handler->found_ll_addr =
604		process_get_neigh_mac(neigh_handler);
605
606found:
607	return neigh_handler->found_ll_addr ? 0 : -1;
608}
609
610int neigh_get_oif_from_src(struct get_neigh_handler *neigh_handler)
611{
612	int oif = -ENODEV;
613	struct addrinfo *src_info;
614	int err;
615
616	err = nl_addr_info(neigh_handler->src, &src_info);
617	if (err) {
618		if (!errno)
619			errno = ENXIO;
620		return oif;
621	}
622
623	oif = get_ifindex(src_info->ai_addr);
624	if (oif <= 0)
625		goto free;
626
627free:
628	freeaddrinfo(src_info);
629	return oif;
630}
631
632static void alloc_zero_based_socket(void)
633{
634	zero_socket = nl_socket_alloc();
635}
636
637int neigh_init_resources(struct get_neigh_handler *neigh_handler, int timeout)
638{
639	int err;
640
641	pthread_once(&device_neigh_alloc, &alloc_zero_based_socket);
642	neigh_handler->sock = nl_socket_alloc();
643	if (neigh_handler->sock == NULL) {
644		errno = ENOMEM;
645		return -1;
646	}
647
648	err = nl_connect(neigh_handler->sock, NETLINK_ROUTE);
649	if (err < 0)
650		goto free_socket;
651
652	err = rtnl_link_alloc_cache(neigh_handler->sock, AF_UNSPEC,
653				    &neigh_handler->link_cache);
654	if (err) {
655		err = -1;
656		errno = ENOMEM;
657		goto close_connection;
658	}
659
660	nl_cache_mngt_provide(neigh_handler->link_cache);
661
662	err = rtnl_route_alloc_cache(neigh_handler->sock, AF_UNSPEC, 0,
663				     &neigh_handler->route_cache);
664	if (err) {
665		err = -1;
666		errno = ENOMEM;
667		goto free_link_cache;
668	}
669
670	nl_cache_mngt_provide(neigh_handler->route_cache);
671
672	err = rtnl_neigh_alloc_cache(neigh_handler->sock,
673				     &neigh_handler->neigh_cache);
674	if (err) {
675		err = -ENOMEM;
676		goto free_route_cache;
677	}
678
679	nl_cache_mngt_provide(neigh_handler->neigh_cache);
680
681	/* init structure */
682	neigh_handler->timeout = timeout;
683	neigh_handler->oif = -1;
684	neigh_handler->filter_neigh = NULL;
685	neigh_handler->found_ll_addr = NULL;
686	neigh_handler->dst = NULL;
687	neigh_handler->src = NULL;
688	neigh_handler->vid = -1;
689
690	return 0;
691
692free_route_cache:
693	nl_cache_mngt_unprovide(neigh_handler->route_cache);
694	nl_cache_free(neigh_handler->route_cache);
695	neigh_handler->route_cache = NULL;
696free_link_cache:
697	nl_cache_mngt_unprovide(neigh_handler->link_cache);
698	nl_cache_free(neigh_handler->link_cache);
699	neigh_handler->link_cache = NULL;
700close_connection:
701	nl_close(neigh_handler->sock);
702free_socket:
703	nl_socket_free(neigh_handler->sock);
704	neigh_handler->sock = NULL;
705	return err;
706}
707
708uint16_t neigh_get_vlan_id_from_dev(struct get_neigh_handler *neigh_handler)
709{
710	struct rtnl_link *link;
711	int vid = 0xffff;
712
713	link = rtnl_link_get(neigh_handler->link_cache, neigh_handler->oif);
714	if (link == NULL) {
715		errno = EINVAL;
716		return vid;
717	}
718
719	if (rtnl_link_is_vlan(link))
720		vid = rtnl_link_vlan_get_id(link);
721	rtnl_link_put(link);
722	return vid >= 0 && vid <= 0xfff ? vid : 0xffff;
723}
724
725void neigh_set_vlan_id(struct get_neigh_handler *neigh_handler, uint16_t vid)
726{
727	if (vid <= 0xfff)
728		neigh_handler->vid = vid;
729}
730
731int neigh_set_dst(struct get_neigh_handler *neigh_handler,
732		  int family, void *buf, size_t size)
733{
734	neigh_handler->dst = nl_addr_build(family, buf, size);
735	return neigh_handler->dst == NULL;
736}
737
738int neigh_set_src(struct get_neigh_handler *neigh_handler,
739		  int family, void *buf, size_t size)
740{
741	neigh_handler->src = nl_addr_build(family, buf, size);
742	return neigh_handler->src == NULL;
743}
744
745void neigh_set_oif(struct get_neigh_handler *neigh_handler, int oif)
746{
747	neigh_handler->oif = oif;
748}
749
750int neigh_get_ll(struct get_neigh_handler *neigh_handler, void *addr_buff,
751		 int addr_size) {
752	int neigh_len;
753
754	if (neigh_handler->found_ll_addr == NULL)
755		return -EINVAL;
756
757	 neigh_len = nl_addr_get_len(neigh_handler->found_ll_addr);
758
759	if (neigh_len > addr_size)
760		return -EINVAL;
761
762	memcpy(addr_buff, nl_addr_get_binary_addr(neigh_handler->found_ll_addr),
763	       neigh_len);
764
765	return neigh_len;
766}
767
768void neigh_free_resources(struct get_neigh_handler *neigh_handler)
769{
770	/* Should be released first because it's holding a reference to dst */
771	if (neigh_handler->filter_neigh != NULL) {
772		rtnl_neigh_put(neigh_handler->filter_neigh);
773		neigh_handler->filter_neigh = NULL;
774	}
775
776	if (neigh_handler->src != NULL) {
777		nl_addr_put(neigh_handler->src);
778		neigh_handler->src = NULL;
779	}
780
781	if (neigh_handler->dst != NULL) {
782		nl_addr_put(neigh_handler->dst);
783		neigh_handler->dst = NULL;
784	}
785
786	if (neigh_handler->found_ll_addr != NULL) {
787		nl_addr_put(neigh_handler->found_ll_addr);
788		neigh_handler->found_ll_addr = NULL;
789	}
790
791	if (neigh_handler->neigh_cache != NULL) {
792		nl_cache_mngt_unprovide(neigh_handler->neigh_cache);
793		nl_cache_free(neigh_handler->neigh_cache);
794		neigh_handler->neigh_cache = NULL;
795	}
796
797	if (neigh_handler->route_cache != NULL) {
798		nl_cache_mngt_unprovide(neigh_handler->route_cache);
799		nl_cache_free(neigh_handler->route_cache);
800		neigh_handler->route_cache = NULL;
801	}
802
803	if (neigh_handler->link_cache != NULL) {
804		nl_cache_mngt_unprovide(neigh_handler->link_cache);
805		nl_cache_free(neigh_handler->link_cache);
806		neigh_handler->link_cache = NULL;
807	}
808
809	if (neigh_handler->sock != NULL) {
810		nl_close(neigh_handler->sock);
811		nl_socket_free(neigh_handler->sock);
812		neigh_handler->sock = NULL;
813	}
814}
815
816int process_get_neigh(struct get_neigh_handler *neigh_handler)
817{
818	struct nl_msg *m;
819	struct rtmsg rmsg = {
820		.rtm_family = nl_addr_get_family(neigh_handler->dst),
821		.rtm_dst_len = nl_addr_get_prefixlen(neigh_handler->dst),
822	};
823	int err;
824
825	m = nlmsg_alloc_simple(RTM_GETROUTE, 0);
826
827	if (m == NULL)
828		return -ENOMEM;
829
830	nlmsg_append(m, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
831
832	nla_put_addr(m, RTA_DST, neigh_handler->dst);
833
834	if (neigh_handler->oif > 0)
835		nla_put_u32(m, RTA_OIF, neigh_handler->oif);
836
837	err = nl_send_auto_complete(neigh_handler->sock, m);
838	nlmsg_free(m);
839	if (err < 0)
840		return err;
841
842	nl_socket_modify_cb(neigh_handler->sock, NL_CB_VALID,
843			    NL_CB_CUSTOM, &get_route_cb, neigh_handler);
844
845	err = nl_recvmsgs_default(neigh_handler->sock);
846
847	return err;
848}
849