1 /* $OpenBSD: interface.c,v 1.25 2019/06/28 13:32:47 deraadt 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 /* ARGSUSED */ 439 static void 440 eigrp_if_hello_timer(int fd, short event, void *arg) 441 { 442 struct eigrp_iface *ei = arg; 443 struct timeval tv; 444 445 send_hello(ei, NULL, 0); 446 447 /* reschedule hello_timer */ 448 timerclear(&tv); 449 tv.tv_sec = ei->hello_interval; 450 if (evtimer_add(&ei->hello_timer, &tv) == -1) 451 fatal("eigrp_if_hello_timer"); 452 } 453 454 static void 455 eigrp_if_start_hello_timer(struct eigrp_iface *ei) 456 { 457 struct timeval tv; 458 459 timerclear(&tv); 460 tv.tv_sec = ei->hello_interval; 461 if (evtimer_add(&ei->hello_timer, &tv) == -1) 462 fatal("eigrp_if_start_hello_timer"); 463 } 464 465 static void 466 eigrp_if_stop_hello_timer(struct eigrp_iface *ei) 467 { 468 if (evtimer_pending(&ei->hello_timer, NULL) && 469 evtimer_del(&ei->hello_timer) == -1) 470 fatal("eigrp_if_stop_hello_timer"); 471 } 472 473 struct ctl_iface * 474 if_to_ctl(struct eigrp_iface *ei) 475 { 476 static struct ctl_iface ictl; 477 struct timeval now; 478 struct nbr *nbr; 479 480 ictl.af = ei->eigrp->af; 481 ictl.as = ei->eigrp->as; 482 memcpy(ictl.name, ei->iface->name, sizeof(ictl.name)); 483 ictl.ifindex = ei->iface->ifindex; 484 switch (ei->eigrp->af) { 485 case AF_INET: 486 ictl.addr.v4.s_addr = if_primary_addr(ei->iface); 487 ictl.prefixlen = if_primary_addr_prefixlen(ei->iface); 488 break; 489 case AF_INET6: 490 ictl.addr.v6 = ei->iface->linklocal; 491 if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal)) 492 ictl.prefixlen = 64; 493 else 494 ictl.prefixlen = 0; 495 break; 496 default: 497 fatalx("if_to_ctl: unknown af"); 498 } 499 ictl.flags = ei->iface->flags; 500 ictl.linkstate = ei->iface->linkstate; 501 ictl.mtu = ei->iface->mtu; 502 ictl.type = ei->iface->type; 503 ictl.if_type = ei->iface->if_type; 504 ictl.baudrate = ei->iface->baudrate; 505 ictl.delay = ei->delay; 506 ictl.bandwidth = ei->bandwidth; 507 ictl.hello_holdtime = ei->hello_holdtime; 508 ictl.hello_interval = ei->hello_interval; 509 ictl.splithorizon = ei->splithorizon; 510 ictl.passive = ei->passive; 511 ictl.nbr_cnt = 0; 512 513 gettimeofday(&now, NULL); 514 if (ei->state != IF_STA_DOWN && ei->uptime != 0) 515 ictl.uptime = now.tv_sec - ei->uptime; 516 else 517 ictl.uptime = 0; 518 519 TAILQ_FOREACH(nbr, &ei->nbr_list, entry) 520 if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF))) 521 ictl.nbr_cnt++; 522 523 return (&ictl); 524 } 525 526 /* misc */ 527 void 528 if_set_sockbuf(int fd) 529 { 530 int bsize; 531 532 bsize = 65535; 533 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 534 sizeof(bsize)) == -1) 535 bsize /= 2; 536 537 if (bsize != 65535) 538 log_warnx("%s: recvbuf size only %d", __func__, bsize); 539 540 bsize = 65535; 541 while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, 542 sizeof(bsize)) == -1) 543 bsize /= 2; 544 545 if (bsize != 65535) 546 log_warnx("%s: sendbuf size only %d", __func__, bsize); 547 } 548 549 static int 550 if_join_ipv4_group(struct iface *iface, struct in_addr *addr) 551 { 552 struct ip_mreq mreq; 553 554 if (iface->group_count_v4++ != 0) 555 /* already joined */ 556 return (0); 557 558 log_debug("%s: interface %s addr %s", __func__, iface->name, 559 inet_ntoa(*addr)); 560 561 mreq.imr_multiaddr = *addr; 562 mreq.imr_interface.s_addr = if_primary_addr(iface); 563 564 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP, 565 (void *)&mreq, sizeof(mreq)) == -1) { 566 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", 567 __func__, iface->name, inet_ntoa(*addr)); 568 return (-1); 569 } 570 571 return (0); 572 } 573 574 static int 575 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) 576 { 577 struct ip_mreq mreq; 578 579 if (--iface->group_count_v4 != 0) 580 /* others still joined */ 581 return (0); 582 583 log_debug("%s: interface %s addr %s", __func__, iface->name, 584 inet_ntoa(*addr)); 585 586 mreq.imr_multiaddr = *addr; 587 mreq.imr_interface.s_addr = if_primary_addr(iface); 588 589 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP, 590 (void *)&mreq, sizeof(mreq)) == -1) { 591 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " 592 "address %s", iface->name, __func__, inet_ntoa(*addr)); 593 return (-1); 594 } 595 596 return (0); 597 } 598 599 int 600 if_set_ipv4_mcast_ttl(int fd, uint8_t ttl) 601 { 602 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 603 (char *)&ttl, sizeof(ttl)) == -1) { 604 log_warn("%s: error setting IP_MULTICAST_TTL to %d", 605 __func__, ttl); 606 return (-1); 607 } 608 609 return (0); 610 } 611 612 int 613 if_set_ipv4_mcast(struct iface *iface) 614 { 615 in_addr_t addr; 616 617 addr = if_primary_addr(iface); 618 619 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF, 620 &addr, sizeof(addr)) == -1) { 621 log_warn("%s: error setting IP_MULTICAST_IF, interface %s", 622 __func__, iface->name); 623 return (-1); 624 } 625 626 return (0); 627 } 628 629 int 630 if_set_ipv4_mcast_loop(int fd) 631 { 632 uint8_t loop = 0; 633 634 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 635 (char *)&loop, sizeof(loop)) == -1) { 636 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__); 637 return (-1); 638 } 639 640 return (0); 641 } 642 643 int 644 if_set_ipv4_recvif(int fd, int enable) 645 { 646 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 647 sizeof(enable)) == -1) { 648 log_warn("%s: error setting IP_RECVIF", __func__); 649 return (-1); 650 } 651 return (0); 652 } 653 654 int 655 if_set_ipv4_hdrincl(int fd) 656 { 657 int hincl = 1; 658 659 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) { 660 log_warn("%s: error setting IP_HDRINCL", __func__); 661 return (-1); 662 } 663 664 return (0); 665 } 666 667 static int 668 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr) 669 { 670 struct ipv6_mreq mreq; 671 672 if (iface->group_count_v6++ != 0) 673 /* already joined */ 674 return (0); 675 676 log_debug("%s: interface %s addr %s", __func__, iface->name, 677 log_in6addr(addr)); 678 679 mreq.ipv6mr_multiaddr = *addr; 680 mreq.ipv6mr_interface = iface->ifindex; 681 682 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP, 683 &mreq, sizeof(mreq)) == -1) { 684 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s", 685 __func__, iface->name, log_in6addr(addr)); 686 return (-1); 687 } 688 689 return (0); 690 } 691 692 static int 693 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr) 694 { 695 struct ipv6_mreq mreq; 696 697 if (--iface->group_count_v6 != 0) 698 /* others still joined */ 699 return (0); 700 701 log_debug("%s: interface %s addr %s", __func__, iface->name, 702 log_in6addr(addr)); 703 704 mreq.ipv6mr_multiaddr = *addr; 705 mreq.ipv6mr_interface = iface->ifindex; 706 707 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 708 (void *)&mreq, sizeof(mreq)) == -1) { 709 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s", 710 __func__, iface->name, log_in6addr(addr)); 711 return (-1); 712 } 713 714 return (0); 715 } 716 717 int 718 if_set_ipv6_mcast(struct iface *iface) 719 { 720 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF, 721 &iface->ifindex, sizeof(iface->ifindex)) == -1) { 722 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s", 723 __func__, iface->name); 724 return (-1); 725 } 726 727 return (0); 728 } 729 730 int 731 if_set_ipv6_mcast_loop(int fd) 732 { 733 unsigned int loop = 0; 734 735 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 736 (unsigned int *)&loop, sizeof(loop)) == -1) { 737 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__); 738 return (-1); 739 } 740 741 return (0); 742 } 743 744 int 745 if_set_ipv6_pktinfo(int fd, int enable) 746 { 747 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable, 748 sizeof(enable)) == -1) { 749 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__); 750 return (-1); 751 } 752 753 return (0); 754 } 755 756 int 757 if_set_ipv6_dscp(int fd, int dscp) 758 { 759 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp, 760 sizeof(dscp)) == -1) { 761 log_warn("%s: error setting IPV6_TCLASS", __func__); 762 return (-1); 763 } 764 765 return (0); 766 } 767