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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 632 static void alloc_zero_based_socket(void) 633 { 634 zero_socket = nl_socket_alloc(); 635 } 636 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 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 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 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 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 745 void neigh_set_oif(struct get_neigh_handler *neigh_handler, int oif) 746 { 747 neigh_handler->oif = oif; 748 } 749 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 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 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