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 */
34 extern 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
47 static pthread_once_t device_neigh_alloc = PTHREAD_ONCE_INIT;
48 static struct nl_sock *zero_socket;
49
50 union sktaddr {
51 struct sockaddr s;
52 struct sockaddr_in s4;
53 struct sockaddr_in6 s6;
54 };
55
56 struct skt {
57 union sktaddr sktaddr;
58 socklen_t len;
59 };
60
set_link_port(union sktaddr * s,__be16 port,int oif)61 static 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
cmp_address(const struct sockaddr * s1,const struct sockaddr * s2)78 static 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
get_ifindex(const struct sockaddr * s)98 static 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
get_neigh_mac(struct get_neigh_handler * neigh_handler)121 static 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
get_neigh_cb_event(struct nl_object * obj,void * arg)143 static 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
get_neigh_cb(struct nl_msg * msg,void * arg)163 static 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
set_neigh_filter(struct get_neigh_handler * neigh_handler,struct rtnl_neigh * filter)174 static void set_neigh_filter(struct get_neigh_handler *neigh_handler,
175 struct rtnl_neigh *filter) {
176 neigh_handler->filter_neigh = filter;
177 }
178
create_filter_neigh_for_dst(struct nl_addr * dst_addr,int oif)179 static 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
create_socket(struct get_neigh_handler * neigh_handler,struct skt * addr_dst,int * psock_fd)197 static 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
create_timer(struct get_neigh_handler * neigh_handler)250 static 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
try_send_to(int sock_fd,void * buff,size_t buf_size,struct skt * addr_dst)280 static 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
process_get_neigh_mac(struct get_neigh_handler * neigh_handler)297 static 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 }
391 select_err:
392 close(timer_fd);
393 close_socket:
394 close(sock_fd);
395 return ll_addr ? ll_addr : neigh_handler->found_ll_addr;
396 }
397
get_mcast_mac_ipv4(struct nl_addr * dst,struct nl_addr ** ll_addr)398 static 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
get_mcast_mac_ipv6(struct nl_addr * dst,struct nl_addr ** ll_addr)414 static 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
get_link_local_mac_ipv6(struct nl_addr * dst,struct nl_addr ** ll_addr)425 static 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
438 static 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
nl_addr_cmp_prefix_msb(void * addr1,int len1,void * addr2,int len2)458 static 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
handle_encoded_mac(struct nl_addr * dst,struct nl_addr ** ll_addr)474 static 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
get_route_cb_parser(struct nl_object * obj,void * arg)511 static 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
573 err_link:
574 rtnl_link_put(link);
575 err:
576 if (neigh_handler->src) {
577 nl_addr_put(neigh_handler->src);
578 neigh_handler->src = NULL;
579 }
580 }
581
get_route_cb(struct nl_msg * msg,void * arg)582 static 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
606 found:
607 return neigh_handler->found_ll_addr ? 0 : -1;
608 }
609
neigh_get_oif_from_src(struct get_neigh_handler * neigh_handler)610 int 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
627 free:
628 freeaddrinfo(src_info);
629 return oif;
630 }
631
alloc_zero_based_socket(void)632 static void alloc_zero_based_socket(void)
633 {
634 zero_socket = nl_socket_alloc();
635 }
636
neigh_init_resources(struct get_neigh_handler * neigh_handler,int timeout)637 int 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
692 free_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;
696 free_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;
700 close_connection:
701 nl_close(neigh_handler->sock);
702 free_socket:
703 nl_socket_free(neigh_handler->sock);
704 neigh_handler->sock = NULL;
705 return err;
706 }
707
neigh_get_vlan_id_from_dev(struct get_neigh_handler * neigh_handler)708 uint16_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
neigh_set_vlan_id(struct get_neigh_handler * neigh_handler,uint16_t vid)725 void 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
neigh_set_dst(struct get_neigh_handler * neigh_handler,int family,void * buf,size_t size)731 int 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
neigh_set_src(struct get_neigh_handler * neigh_handler,int family,void * buf,size_t size)738 int 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
neigh_set_oif(struct get_neigh_handler * neigh_handler,int oif)745 void neigh_set_oif(struct get_neigh_handler *neigh_handler, int oif)
746 {
747 neigh_handler->oif = oif;
748 }
749
neigh_get_ll(struct get_neigh_handler * neigh_handler,void * addr_buff,int addr_size)750 int 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
neigh_free_resources(struct get_neigh_handler * neigh_handler)768 void 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
process_get_neigh(struct get_neigh_handler * neigh_handler)816 int 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