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