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