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