1 /* $OpenBSD: interface.c,v 1.26 2023/03/08 04:43:13 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/ioctl.h> 24 #include <arpa/inet.h> 25 26 #include <ctype.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "eigrpd.h" 32 #include "eigrpe.h" 33 #include "log.h" 34 35 static __inline int iface_id_compare(struct eigrp_iface *, 36 struct eigrp_iface *); 37 static struct iface *if_new(struct eigrpd_conf *, struct kif *); 38 static void if_del(struct iface *); 39 static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); 40 static void eigrp_if_start(struct eigrp_iface *); 41 static void eigrp_if_reset(struct eigrp_iface *); 42 static void eigrp_if_hello_timer(int, short, void *); 43 static void eigrp_if_start_hello_timer(struct eigrp_iface *); 44 static void eigrp_if_stop_hello_timer(struct eigrp_iface *); 45 static int if_join_ipv4_group(struct iface *, struct in_addr *); 46 static int if_leave_ipv4_group(struct iface *, struct in_addr *); 47 static int if_join_ipv6_group(struct iface *, struct in6_addr *); 48 static int if_leave_ipv6_group(struct iface *, struct in6_addr *); 49 50 RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare) 51 52 struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id); 53 54 static __inline int 55 iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b) 56 { 57 return (a->ifaceid - b->ifaceid); 58 } 59 60 static struct iface * 61 if_new(struct eigrpd_conf *xconf, struct kif *kif) 62 { 63 struct iface *iface; 64 65 if ((iface = calloc(1, sizeof(*iface))) == NULL) 66 fatal("if_new: calloc"); 67 68 TAILQ_INIT(&iface->ei_list); 69 TAILQ_INIT(&iface->addr_list); 70 71 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 72 73 /* get type */ 74 if (kif->flags & IFF_POINTOPOINT) 75 iface->type = IF_TYPE_POINTOPOINT; 76 if (kif->flags & IFF_BROADCAST && 77 kif->flags & IFF_MULTICAST) 78 iface->type = IF_TYPE_BROADCAST; 79 if (kif->flags & IFF_LOOPBACK) 80 iface->type = IF_TYPE_POINTOPOINT; 81 82 /* get index and flags */ 83 iface->mtu = kif->mtu; 84 iface->ifindex = kif->ifindex; 85 iface->rdomain = kif->rdomain; 86 iface->flags = kif->flags; 87 iface->linkstate = kif->link_state; 88 iface->if_type = kif->if_type; 89 iface->baudrate = kif->baudrate; 90 91 TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry); 92 93 return (iface); 94 } 95 96 static void 97 if_del(struct iface *iface) 98 { 99 struct if_addr *if_addr; 100 101 log_debug("%s: interface %s", __func__, iface->name); 102 103 while ((if_addr = TAILQ_FIRST(&iface->addr_list)) != NULL) { 104 TAILQ_REMOVE(&iface->addr_list, if_addr, entry); 105 free(if_addr); 106 } 107 108 TAILQ_REMOVE(&econf->iface_list, iface, entry); 109 free(iface); 110 } 111 112 struct iface * 113 if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex) 114 { 115 struct iface *iface; 116 117 TAILQ_FOREACH(iface, &xconf->iface_list, entry) 118 if (iface->ifindex == ifindex) 119 return (iface); 120 121 return (NULL); 122 } 123 124 void 125 if_addr_new(struct iface *iface, struct kaddr *ka) 126 { 127 struct if_addr *if_addr; 128 struct eigrp_iface *ei; 129 130 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) { 131 iface->linklocal = ka->addr.v6; 132 if_update(iface, AF_INET6); 133 return; 134 } 135 136 if (if_addr_lookup(&iface->addr_list, ka) != NULL) 137 return; 138 139 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) 140 fatal("if_addr_new: calloc"); 141 if_addr->af = ka->af; 142 if_addr->addr = ka->addr; 143 if_addr->prefixlen = ka->prefixlen; 144 if_addr->dstbrd = ka->dstbrd; 145 TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry); 146 147 TAILQ_FOREACH(ei, &iface->ei_list, i_entry) 148 if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af) 149 eigrpe_orig_local_route(ei, if_addr, 0); 150 151 if (if_addr->af == AF_INET) 152 if_update(iface, AF_INET); 153 } 154 155 void 156 if_addr_del(struct iface *iface, struct kaddr *ka) 157 { 158 struct if_addr *if_addr; 159 struct eigrp_iface *ei; 160 int af = ka->af; 161 162 if (ka->af == AF_INET6 && 163 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) { 164 memset(&iface->linklocal, 0, sizeof(iface->linklocal)); 165 if_update(iface, AF_INET6); 166 return; 167 } 168 169 if_addr = if_addr_lookup(&iface->addr_list, ka); 170 if (if_addr == NULL) 171 return; 172 173 TAILQ_FOREACH(ei, &iface->ei_list, i_entry) 174 if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af) 175 eigrpe_orig_local_route(ei, if_addr, 1); 176 177 TAILQ_REMOVE(&iface->addr_list, if_addr, entry); 178 free(if_addr); 179 180 if (af == AF_INET) 181 if_update(iface, AF_INET); 182 } 183 184 static struct if_addr * 185 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka) 186 { 187 struct if_addr *if_addr; 188 int af = ka->af; 189 190 TAILQ_FOREACH(if_addr, addr_list, entry) 191 if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) && 192 if_addr->prefixlen == ka->prefixlen && 193 !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd)) 194 return (if_addr); 195 196 return (NULL); 197 } 198 199 in_addr_t 200 if_primary_addr(struct iface *iface) 201 { 202 struct if_addr *if_addr; 203 204 TAILQ_FOREACH(if_addr, &iface->addr_list, entry) 205 if (if_addr->af == AF_INET) 206 return (if_addr->addr.v4.s_addr); 207 208 return (INADDR_ANY); 209 } 210 211 uint8_t 212 if_primary_addr_prefixlen(struct iface *iface) 213 { 214 struct if_addr *if_addr; 215 216 TAILQ_FOREACH(if_addr, &iface->addr_list, entry) 217 if (if_addr->af == AF_INET) 218 return (if_addr->prefixlen); 219 220 return (0); 221 } 222 223 /* up/down events */ 224 void 225 if_update(struct iface *iface, int af) 226 { 227 struct eigrp_iface *ei; 228 int link_ok; 229 int addr_ok, addr4_ok = 0, addr6_ok = 0; 230 struct if_addr *if_addr; 231 232 link_ok = (iface->flags & IFF_UP) && 233 LINK_STATE_IS_UP(iface->linkstate); 234 235 /* 236 * NOTE: for EIGRPv4, each interface should have at least one valid 237 * IP address otherwise they can not be enabled in the routing domain. 238 */ 239 TAILQ_FOREACH(if_addr, &iface->addr_list, entry) { 240 if (if_addr->af == AF_INET) { 241 addr4_ok = 1; 242 break; 243 } 244 } 245 /* for IPv6 the link-local address is enough. */ 246 if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal)) 247 addr6_ok = 1; 248 249 TAILQ_FOREACH(ei, &iface->ei_list, i_entry) { 250 if (af != AF_UNSPEC && ei->eigrp->af != af) 251 continue; 252 253 switch (ei->eigrp->af) { 254 case AF_INET: 255 addr_ok = addr4_ok; 256 break; 257 case AF_INET6: 258 addr_ok = addr6_ok; 259 break; 260 default: 261 fatalx("if_update: unknown af"); 262 } 263 264 if (ei->state == IF_STA_DOWN) { 265 if (!link_ok || !addr_ok) 266 continue; 267 ei->state = IF_STA_ACTIVE; 268 eigrp_if_start(ei); 269 } else if (ei->state == IF_STA_ACTIVE) { 270 if (link_ok && addr_ok) 271 continue; 272 ei->state = IF_STA_DOWN; 273 eigrp_if_reset(ei); 274 } 275 } 276 } 277 278 struct eigrp_iface * 279 eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif) 280 { 281 struct iface *iface; 282 struct eigrp_iface *ei; 283 static uint32_t ifacecnt = 1; 284 285 iface = if_lookup(xconf, kif->ifindex); 286 if (iface == NULL) 287 iface = if_new(xconf, kif); 288 289 if ((ei = calloc(1, sizeof(*ei))) == NULL) 290 fatal("eigrp_if_new: calloc"); 291 292 ei->state = IF_STA_DOWN; 293 /* get next unused ifaceid */ 294 while (eigrp_if_lookup_id(ifacecnt++)) 295 ; 296 ei->ifaceid = ifacecnt; 297 ei->eigrp = eigrp; 298 ei->iface = iface; 299 if (ei->iface->flags & IFF_LOOPBACK) 300 ei->passive = 1; 301 302 TAILQ_INIT(&ei->nbr_list); 303 TAILQ_INIT(&ei->update_list); 304 TAILQ_INIT(&ei->query_list); 305 TAILQ_INIT(&ei->summary_list); 306 TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry); 307 TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry); 308 if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL) 309 fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed"); 310 311 return (ei); 312 } 313 314 void 315 eigrp_if_del(struct eigrp_iface *ei) 316 { 317 struct summary_addr *summary; 318 319 RB_REMOVE(iface_id_head, &ifaces_by_id, ei); 320 TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry); 321 TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry); 322 while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) { 323 TAILQ_REMOVE(&ei->summary_list, summary, entry); 324 free(summary); 325 } 326 message_list_clr(&ei->query_list); 327 message_list_clr(&ei->update_list); 328 329 if (ei->state == IF_STA_ACTIVE) 330 eigrp_if_reset(ei); 331 332 if (TAILQ_EMPTY(&ei->iface->ei_list)) 333 if_del(ei->iface); 334 335 free(ei); 336 } 337 338 struct eigrp_iface * 339 eigrp_if_lookup(struct iface *iface, int af, uint16_t as) 340 { 341 struct eigrp_iface *ei; 342 343 TAILQ_FOREACH(ei, &iface->ei_list, i_entry) 344 if (ei->eigrp->af == af && 345 ei->eigrp->as == as) 346 return (ei); 347 348 return (NULL); 349 } 350 351 struct eigrp_iface * 352 eigrp_if_lookup_id(uint32_t ifaceid) 353 { 354 struct eigrp_iface e; 355 e.ifaceid = ifaceid; 356 return (RB_FIND(iface_id_head, &ifaces_by_id, &e)); 357 } 358 359 static void 360 eigrp_if_start(struct eigrp_iface *ei) 361 { 362 struct eigrp *eigrp = ei->eigrp; 363 struct timeval now; 364 struct if_addr *if_addr; 365 union eigrpd_addr addr; 366 367 log_debug("%s: %s as %u family %s", __func__, ei->iface->name, 368 eigrp->as, af_name(eigrp->af)); 369 370 gettimeofday(&now, NULL); 371 ei->uptime = now.tv_sec; 372 373 /* init the dummy self neighbor */ 374 memset(&addr, 0, sizeof(addr)); 375 ei->self = nbr_new(ei, &addr, 0, 1); 376 nbr_init(ei->self); 377 378 TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry) { 379 if (if_addr->af != eigrp->af) 380 continue; 381 382 eigrpe_orig_local_route(ei, if_addr, 0); 383 } 384 385 if (ei->passive) 386 return; 387 388 switch (eigrp->af) { 389 case AF_INET: 390 if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4)) 391 return; 392 break; 393 case AF_INET6: 394 if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6)) 395 return; 396 break; 397 default: 398 fatalx("eigrp_if_start: unknown af"); 399 } 400 401 evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei); 402 eigrp_if_start_hello_timer(ei); 403 } 404 405 static void 406 eigrp_if_reset(struct eigrp_iface *ei) 407 { 408 struct eigrp *eigrp = ei->eigrp; 409 struct nbr *nbr; 410 411 log_debug("%s: %s as %u family %s", __func__, ei->iface->name, 412 eigrp->as, af_name(eigrp->af)); 413 414 /* the rde will withdraw the connected route for us */ 415 416 while ((nbr = TAILQ_FIRST(&ei->nbr_list)) != NULL) 417 nbr_del(nbr); 418 419 if (ei->passive) 420 return; 421 422 /* try to cleanup */ 423 switch (eigrp->af) { 424 case AF_INET: 425 if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4); 426 break; 427 case AF_INET6: 428 if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6); 429 break; 430 default: 431 fatalx("eigrp_if_reset: unknown af"); 432 } 433 434 eigrp_if_stop_hello_timer(ei); 435 } 436 437 /* timers */ 438 static void 439 eigrp_if_hello_timer(int fd, short event, void *arg) 440 { 441 struct eigrp_iface *ei = arg; 442 struct timeval tv; 443 444 send_hello(ei, NULL, 0); 445 446 /* reschedule hello_timer */ 447 timerclear(&tv); 448 tv.tv_sec = ei->hello_interval; 449 if (evtimer_add(&ei->hello_timer, &tv) == -1) 450 fatal("eigrp_if_hello_timer"); 451 } 452 453 static void 454 eigrp_if_start_hello_timer(struct eigrp_iface *ei) 455 { 456 struct timeval tv; 457 458 timerclear(&tv); 459 tv.tv_sec = ei->hello_interval; 460 if (evtimer_add(&ei->hello_timer, &tv) == -1) 461 fatal("eigrp_if_start_hello_timer"); 462 } 463 464 static void 465 eigrp_if_stop_hello_timer(struct eigrp_iface *ei) 466 { 467 if (evtimer_pending(&ei->hello_timer, NULL) && 468 evtimer_del(&ei->hello_timer) == -1) 469 fatal("eigrp_if_stop_hello_timer"); 470 } 471 472 struct ctl_iface * 473 if_to_ctl(struct eigrp_iface *ei) 474 { 475 static struct ctl_iface ictl; 476 struct timeval now; 477 struct nbr *nbr; 478 479 ictl.af = ei->eigrp->af; 480 ictl.as = ei->eigrp->as; 481 memcpy(ictl.name, ei->iface->name, sizeof(ictl.name)); 482 ictl.ifindex = ei->iface->ifindex; 483 switch (ei->eigrp->af) { 484 case AF_INET: 485 ictl.addr.v4.s_addr = if_primary_addr(ei->iface); 486 ictl.prefixlen = if_primary_addr_prefixlen(ei->iface); 487 break; 488 case AF_INET6: 489 ictl.addr.v6 = ei->iface->linklocal; 490 if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal)) 491 ictl.prefixlen = 64; 492 else 493 ictl.prefixlen = 0; 494 break; 495 default: 496 fatalx("if_to_ctl: unknown af"); 497 } 498 ictl.flags = ei->iface->flags; 499 ictl.linkstate = ei->iface->linkstate; 500 ictl.mtu = ei->iface->mtu; 501 ictl.type = ei->iface->type; 502 ictl.if_type = ei->iface->if_type; 503 ictl.baudrate = ei->iface->baudrate; 504 ictl.delay = ei->delay; 505 ictl.bandwidth = ei->bandwidth; 506 ictl.hello_holdtime = ei->hello_holdtime; 507 ictl.hello_interval = ei->hello_interval; 508 ictl.splithorizon = ei->splithorizon; 509 ictl.passive = ei->passive; 510 ictl.nbr_cnt = 0; 511 512 gettimeofday(&now, NULL); 513 if (ei->state != IF_STA_DOWN && ei->uptime != 0) 514 ictl.uptime = now.tv_sec - ei->uptime; 515 else 516 ictl.uptime = 0; 517 518 TAILQ_FOREACH(nbr, &ei->nbr_list, entry) 519 if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF))) 520 ictl.nbr_cnt++; 521 522 return (&ictl); 523 } 524 525 /* misc */ 526 void 527 if_set_sockbuf(int fd) 528 { 529 int bsize; 530 531 bsize = 65535; 532 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 533 sizeof(bsize)) == -1) 534 bsize /= 2; 535 536 if (bsize != 65535) 537 log_warnx("%s: recvbuf size only %d", __func__, bsize); 538 539 bsize = 65535; 540 while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, 541 sizeof(bsize)) == -1) 542 bsize /= 2; 543 544 if (bsize != 65535) 545 log_warnx("%s: sendbuf size only %d", __func__, bsize); 546 } 547 548 static int 549 if_join_ipv4_group(struct iface *iface, struct in_addr *addr) 550 { 551 struct ip_mreq mreq; 552 553 if (iface->group_count_v4++ != 0) 554 /* already joined */ 555 return (0); 556 557 log_debug("%s: interface %s addr %s", __func__, iface->name, 558 inet_ntoa(*addr)); 559 560 mreq.imr_multiaddr = *addr; 561 mreq.imr_interface.s_addr = if_primary_addr(iface); 562 563 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP, 564 (void *)&mreq, sizeof(mreq)) == -1) { 565 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", 566 __func__, iface->name, inet_ntoa(*addr)); 567 return (-1); 568 } 569 570 return (0); 571 } 572 573 static int 574 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) 575 { 576 struct ip_mreq mreq; 577 578 if (--iface->group_count_v4 != 0) 579 /* others still joined */ 580 return (0); 581 582 log_debug("%s: interface %s addr %s", __func__, iface->name, 583 inet_ntoa(*addr)); 584 585 mreq.imr_multiaddr = *addr; 586 mreq.imr_interface.s_addr = if_primary_addr(iface); 587 588 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP, 589 (void *)&mreq, sizeof(mreq)) == -1) { 590 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " 591 "address %s", iface->name, __func__, inet_ntoa(*addr)); 592 return (-1); 593 } 594 595 return (0); 596 } 597 598 int 599 if_set_ipv4_mcast_ttl(int fd, uint8_t ttl) 600 { 601 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 602 (char *)&ttl, sizeof(ttl)) == -1) { 603 log_warn("%s: error setting IP_MULTICAST_TTL to %d", 604 __func__, ttl); 605 return (-1); 606 } 607 608 return (0); 609 } 610 611 int 612 if_set_ipv4_mcast(struct iface *iface) 613 { 614 in_addr_t addr; 615 616 addr = if_primary_addr(iface); 617 618 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF, 619 &addr, sizeof(addr)) == -1) { 620 log_warn("%s: error setting IP_MULTICAST_IF, interface %s", 621 __func__, iface->name); 622 return (-1); 623 } 624 625 return (0); 626 } 627 628 int 629 if_set_ipv4_mcast_loop(int fd) 630 { 631 uint8_t loop = 0; 632 633 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 634 (char *)&loop, sizeof(loop)) == -1) { 635 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__); 636 return (-1); 637 } 638 639 return (0); 640 } 641 642 int 643 if_set_ipv4_recvif(int fd, int enable) 644 { 645 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 646 sizeof(enable)) == -1) { 647 log_warn("%s: error setting IP_RECVIF", __func__); 648 return (-1); 649 } 650 return (0); 651 } 652 653 int 654 if_set_ipv4_hdrincl(int fd) 655 { 656 int hincl = 1; 657 658 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) { 659 log_warn("%s: error setting IP_HDRINCL", __func__); 660 return (-1); 661 } 662 663 return (0); 664 } 665 666 static int 667 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr) 668 { 669 struct ipv6_mreq mreq; 670 671 if (iface->group_count_v6++ != 0) 672 /* already joined */ 673 return (0); 674 675 log_debug("%s: interface %s addr %s", __func__, iface->name, 676 log_in6addr(addr)); 677 678 mreq.ipv6mr_multiaddr = *addr; 679 mreq.ipv6mr_interface = iface->ifindex; 680 681 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP, 682 &mreq, sizeof(mreq)) == -1) { 683 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s", 684 __func__, iface->name, log_in6addr(addr)); 685 return (-1); 686 } 687 688 return (0); 689 } 690 691 static int 692 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr) 693 { 694 struct ipv6_mreq mreq; 695 696 if (--iface->group_count_v6 != 0) 697 /* others still joined */ 698 return (0); 699 700 log_debug("%s: interface %s addr %s", __func__, iface->name, 701 log_in6addr(addr)); 702 703 mreq.ipv6mr_multiaddr = *addr; 704 mreq.ipv6mr_interface = iface->ifindex; 705 706 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 707 (void *)&mreq, sizeof(mreq)) == -1) { 708 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s", 709 __func__, iface->name, log_in6addr(addr)); 710 return (-1); 711 } 712 713 return (0); 714 } 715 716 int 717 if_set_ipv6_mcast(struct iface *iface) 718 { 719 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF, 720 &iface->ifindex, sizeof(iface->ifindex)) == -1) { 721 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s", 722 __func__, iface->name); 723 return (-1); 724 } 725 726 return (0); 727 } 728 729 int 730 if_set_ipv6_mcast_loop(int fd) 731 { 732 unsigned int loop = 0; 733 734 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 735 (unsigned int *)&loop, sizeof(loop)) == -1) { 736 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__); 737 return (-1); 738 } 739 740 return (0); 741 } 742 743 int 744 if_set_ipv6_pktinfo(int fd, int enable) 745 { 746 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable, 747 sizeof(enable)) == -1) { 748 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__); 749 return (-1); 750 } 751 752 return (0); 753 } 754 755 int 756 if_set_ipv6_dscp(int fd, int dscp) 757 { 758 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp, 759 sizeof(dscp)) == -1) { 760 log_warn("%s: error setting IPV6_TCLASS", __func__); 761 return (-1); 762 } 763 764 return (0); 765 } 766