1 /* $OpenBSD: interface.c,v 1.58 2007/02/01 13:25:28 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/ioctl.h> 22 #include <sys/time.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if.h> 27 #include <net/if_types.h> 28 #include <ctype.h> 29 #include <err.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <event.h> 35 36 #include "ospfd.h" 37 #include "ospf.h" 38 #include "log.h" 39 #include "ospfe.h" 40 41 void if_hello_timer(int, short, void *); 42 void if_start_hello_timer(struct iface *); 43 void if_stop_hello_timer(struct iface *); 44 void if_stop_wait_timer(struct iface *); 45 void if_wait_timer(int, short, void *); 46 void if_start_wait_timer(struct iface *); 47 void if_stop_wait_timer(struct iface *); 48 struct nbr *if_elect(struct nbr *, struct nbr *); 49 50 struct { 51 int state; 52 enum iface_event event; 53 enum iface_action action; 54 int new_state; 55 } iface_fsm[] = { 56 /* current state event that happened action to take resulting state */ 57 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 58 {IF_STA_WAITING, IF_EVT_BACKUP_SEEN, IF_ACT_ELECT, 0}, 59 {IF_STA_WAITING, IF_EVT_WTIMER, IF_ACT_ELECT, 0}, 60 {IF_STA_ANY, IF_EVT_WTIMER, IF_ACT_NOTHING, 0}, 61 {IF_STA_WAITING, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 62 {IF_STA_MULTI, IF_EVT_NBR_CHNG, IF_ACT_ELECT, 0}, 63 {IF_STA_ANY, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 64 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 65 {IF_STA_ANY, IF_EVT_LOOP, IF_ACT_RST, IF_STA_LOOPBACK}, 66 {IF_STA_LOOPBACK, IF_EVT_UNLOOP, IF_ACT_NOTHING, IF_STA_DOWN}, 67 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 68 }; 69 70 static int vlink_cnt = 0; 71 72 const char * const if_event_names[] = { 73 "NOTHING", 74 "UP", 75 "WAITTIMER", 76 "BACKUPSEEN", 77 "NEIGHBORCHANGE", 78 "LOOP", 79 "UNLOOP", 80 "DOWN" 81 }; 82 83 const char * const if_action_names[] = { 84 "NOTHING", 85 "START", 86 "ELECT", 87 "RESET" 88 }; 89 90 int 91 if_fsm(struct iface *iface, enum iface_event event) 92 { 93 int old_state; 94 int new_state = 0; 95 int i, ret = 0; 96 97 old_state = iface->state; 98 99 for (i = 0; iface_fsm[i].state != -1; i++) 100 if ((iface_fsm[i].state & old_state) && 101 (iface_fsm[i].event == event)) { 102 new_state = iface_fsm[i].new_state; 103 break; 104 } 105 106 if (iface_fsm[i].state == -1) { 107 /* event outside of the defined fsm, ignore it. */ 108 log_debug("if_fsm: interface %s, " 109 "event %s not expected in state %s", iface->name, 110 if_event_names[event], if_state_name(old_state)); 111 return (0); 112 } 113 114 switch (iface_fsm[i].action) { 115 case IF_ACT_STRT: 116 ret = if_act_start(iface); 117 break; 118 case IF_ACT_ELECT: 119 ret = if_act_elect(iface); 120 break; 121 case IF_ACT_RST: 122 ret = if_act_reset(iface); 123 break; 124 case IF_ACT_NOTHING: 125 /* do nothing */ 126 break; 127 } 128 129 if (ret) { 130 log_debug("if_fsm: error changing state for interface %s, " 131 "event %s, state %s", iface->name, if_event_names[event], 132 if_state_name(old_state)); 133 return (-1); 134 } 135 136 if (new_state != 0) 137 iface->state = new_state; 138 139 if (iface->state != old_state) 140 orig_rtr_lsa(iface->area); 141 142 log_debug("if_fsm: event %s resulted in action %s and changing " 143 "state for interface %s from %s to %s", 144 if_event_names[event], if_action_names[iface_fsm[i].action], 145 iface->name, if_state_name(old_state), if_state_name(iface->state)); 146 147 return (ret); 148 } 149 150 struct iface * 151 if_new(struct kif *kif, struct kif_addr *ka) 152 { 153 struct iface *iface; 154 155 if ((iface = calloc(1, sizeof(*iface))) == NULL) 156 err(1, "if_new: calloc"); 157 158 iface->state = IF_STA_DOWN; 159 160 LIST_INIT(&iface->nbr_list); 161 TAILQ_INIT(&iface->ls_ack_list); 162 TAILQ_INIT(&iface->auth_md_list); 163 164 iface->crypt_seq_num = arc4random() & 0x0fffffff; 165 166 if (kif == NULL) { 167 iface->type = IF_TYPE_VIRTUALLINK; 168 snprintf(iface->name, sizeof(iface->name), "vlink%d", 169 vlink_cnt++); 170 iface->flags |= IFF_UP; 171 iface->mtu = IP_MSS; 172 return (iface); 173 } 174 175 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 176 177 /* get type */ 178 if (kif->flags & IFF_POINTOPOINT) 179 iface->type = IF_TYPE_POINTOPOINT; 180 if (kif->flags & IFF_BROADCAST && 181 kif->flags & IFF_MULTICAST) 182 iface->type = IF_TYPE_BROADCAST; 183 if (kif->flags & IFF_LOOPBACK) { 184 iface->type = IF_TYPE_POINTOPOINT; 185 iface->state = IF_STA_LOOPBACK; 186 } 187 188 /* get mtu, index and flags */ 189 iface->mtu = kif->mtu; 190 iface->ifindex = kif->ifindex; 191 iface->flags = kif->flags; 192 iface->linkstate = kif->link_state; 193 iface->media_type = kif->media_type; 194 195 /* set address, mask and p2p addr */ 196 iface->addr = ka->addr; 197 iface->mask = ka->mask; 198 if (kif->flags & IFF_POINTOPOINT) { 199 iface->dst = ka->dstbrd; 200 } 201 202 return (iface); 203 } 204 205 void 206 if_del(struct iface *iface) 207 { 208 struct nbr *nbr = NULL; 209 210 log_debug("if_del: interface %s", iface->name); 211 212 /* clear lists etc */ 213 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 214 nbr_del(nbr); 215 216 if (evtimer_pending(&iface->hello_timer, NULL)) 217 evtimer_del(&iface->hello_timer); 218 if (evtimer_pending(&iface->wait_timer, NULL)) 219 evtimer_del(&iface->wait_timer); 220 if (evtimer_pending(&iface->lsack_tx_timer, NULL)) 221 evtimer_del(&iface->lsack_tx_timer); 222 223 ls_ack_list_clr(iface); 224 md_list_clr(&iface->auth_md_list); 225 free(iface); 226 } 227 228 void 229 if_init(struct ospfd_conf *xconf, struct iface *iface) 230 { 231 /* init the dummy local neighbor */ 232 iface->self = nbr_new(ospfe_router_id(), iface, 1); 233 234 /* set event handlers for interface */ 235 evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface); 236 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 237 evtimer_set(&iface->wait_timer, if_wait_timer, iface); 238 239 iface->fd = xconf->ospf_socket; 240 } 241 242 /* timers */ 243 /* ARGSUSED */ 244 void 245 if_hello_timer(int fd, short event, void *arg) 246 { 247 struct iface *iface = arg; 248 struct timeval tv; 249 250 send_hello(iface); 251 252 /* reschedule hello_timer */ 253 timerclear(&tv); 254 tv.tv_sec = iface->hello_interval; 255 if (evtimer_add(&iface->hello_timer, &tv) == -1) 256 fatal("if_hello_timer"); 257 } 258 259 void 260 if_start_hello_timer(struct iface *iface) 261 { 262 struct timeval tv; 263 264 timerclear(&tv); 265 if (evtimer_add(&iface->hello_timer, &tv) == -1) 266 fatal("if_start_hello_timer"); 267 } 268 269 void 270 if_stop_hello_timer(struct iface *iface) 271 { 272 if (evtimer_del(&iface->hello_timer) == -1) 273 fatal("if_stop_hello_timer"); 274 } 275 276 /* ARGSUSED */ 277 void 278 if_wait_timer(int fd, short event, void *arg) 279 { 280 struct iface *iface = arg; 281 282 if_fsm(iface, IF_EVT_WTIMER); 283 } 284 285 void 286 if_start_wait_timer(struct iface *iface) 287 { 288 struct timeval tv; 289 290 timerclear(&tv); 291 tv.tv_sec = iface->dead_interval; 292 if (evtimer_add(&iface->wait_timer, &tv) == -1) 293 fatal("if_start_wait_timer"); 294 } 295 296 void 297 if_stop_wait_timer(struct iface *iface) 298 { 299 if (evtimer_del(&iface->wait_timer) == -1) 300 fatal("if_stop_wait_timer"); 301 } 302 303 /* actions */ 304 int 305 if_act_start(struct iface *iface) 306 { 307 struct in_addr addr; 308 struct timeval now; 309 310 if (!((iface->flags & IFF_UP) && 311 (LINK_STATE_IS_UP(iface->linkstate) || 312 (iface->linkstate == LINK_STATE_UNKNOWN && 313 iface->media_type != IFT_CARP)))) { 314 log_debug("if_act_start: interface %s link down", 315 iface->name); 316 return (0); 317 } 318 319 if (iface->media_type == IFT_CARP && iface->passive == 0) { 320 /* force passive mode on carp interfaces */ 321 log_warnx("if_act_start: forcing interface %s to passive", 322 iface->name); 323 iface->passive = 1; 324 } 325 326 if (iface->passive) { 327 /* for an update of stub network entries */ 328 orig_rtr_lsa(iface->area); 329 return (0); 330 } 331 332 gettimeofday(&now, NULL); 333 iface->uptime = now.tv_sec; 334 335 switch (iface->type) { 336 case IF_TYPE_POINTOPOINT: 337 inet_aton(AllSPFRouters, &addr); 338 if (if_join_group(iface, &addr)) 339 return (-1); 340 iface->state = IF_STA_POINTTOPOINT; 341 break; 342 case IF_TYPE_VIRTUALLINK: 343 iface->state = IF_STA_POINTTOPOINT; 344 break; 345 case IF_TYPE_POINTOMULTIPOINT: 346 case IF_TYPE_NBMA: 347 log_debug("if_act_start: type %s not supported, interface %s", 348 if_type_name(iface->type), iface->name); 349 return (-1); 350 case IF_TYPE_BROADCAST: 351 inet_aton(AllSPFRouters, &addr); 352 if (if_join_group(iface, &addr)) 353 return (-1); 354 if (iface->priority == 0) { 355 iface->state = IF_STA_DROTHER; 356 } else { 357 iface->state = IF_STA_WAITING; 358 if_start_wait_timer(iface); 359 } 360 break; 361 default: 362 fatalx("if_act_start: unknown interface type"); 363 } 364 365 /* hello timer needs to be started in any case */ 366 if_start_hello_timer(iface); 367 return (0); 368 } 369 370 struct nbr * 371 if_elect(struct nbr *a, struct nbr *b) 372 { 373 if (a->priority > b->priority) 374 return (a); 375 if (a->priority < b->priority) 376 return (b); 377 if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr)) 378 return (a); 379 return (b); 380 } 381 382 int 383 if_act_elect(struct iface *iface) 384 { 385 struct in_addr addr; 386 struct nbr *nbr, *bdr = NULL, *dr = NULL; 387 int round = 0; 388 int changed = 0; 389 int old_state; 390 char b1[16], b2[16], b3[16], b4[16]; 391 392 start: 393 /* elect backup designated router */ 394 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 395 if (nbr->priority == 0 || nbr == dr || /* not electable */ 396 nbr->state & NBR_STA_PRELIM || /* not available */ 397 nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */ 398 continue; 399 if (bdr != NULL) { 400 /* 401 * routers announcing themselves as BDR have higher 402 * precedence over those routers announcing a 403 * different BDR. 404 */ 405 if (nbr->bdr.s_addr == nbr->addr.s_addr) { 406 if (bdr->bdr.s_addr == bdr->addr.s_addr) 407 bdr = if_elect(bdr, nbr); 408 else 409 bdr = nbr; 410 } else if (bdr->bdr.s_addr != bdr->addr.s_addr) 411 bdr = if_elect(bdr, nbr); 412 } else 413 bdr = nbr; 414 } 415 416 /* elect designated router */ 417 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 418 if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM || 419 (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr)) 420 /* only DR may be elected check priority too */ 421 continue; 422 if (dr == NULL) 423 dr = nbr; 424 else 425 dr = if_elect(dr, nbr); 426 } 427 428 if (dr == NULL) { 429 /* no designate router found use backup DR */ 430 dr = bdr; 431 bdr = NULL; 432 } 433 434 /* 435 * if we are involved in the election (e.g. new DR or no 436 * longer BDR) redo the election 437 */ 438 if (round == 0 && 439 ((iface->self == dr && iface->self != iface->dr) || 440 (iface->self != dr && iface->self == iface->dr) || 441 (iface->self == bdr && iface->self != iface->bdr) || 442 (iface->self != bdr && iface->self == iface->bdr))) { 443 /* 444 * Reset announced DR/BDR to calculated one, so 445 * that we may get elected in the second round. 446 * This is needed to drop from a DR to a BDR. 447 */ 448 iface->self->dr.s_addr = dr->addr.s_addr; 449 if (bdr) 450 iface->self->bdr.s_addr = bdr->addr.s_addr; 451 round = 1; 452 goto start; 453 } 454 455 log_debug("if_act_elect: interface %s old dr %s new dr %s, " 456 "old bdr %s new bdr %s", iface->name, 457 iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) : 458 "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none", 459 iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) : 460 "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) : 461 "none"); 462 463 /* 464 * After the second round still DR or BDR change state to DR or BDR, 465 * etc. 466 */ 467 old_state = iface->state; 468 if (dr == iface->self) 469 iface->state = IF_STA_DR; 470 else if (bdr == iface->self) 471 iface->state = IF_STA_BACKUP; 472 else 473 iface->state = IF_STA_DROTHER; 474 475 /* TODO if iface is NBMA send all non eligible neighbors event Start */ 476 477 /* 478 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way 479 */ 480 if (iface->dr != dr || iface->bdr != bdr) 481 changed = 1; 482 483 iface->dr = dr; 484 iface->bdr = bdr; 485 486 if (changed) { 487 inet_aton(AllDRouters, &addr); 488 if (old_state & IF_STA_DRORBDR && 489 (iface->state & IF_STA_DRORBDR) == 0) { 490 if (if_leave_group(iface, &addr)) 491 return (-1); 492 } else if ((old_state & IF_STA_DRORBDR) == 0 && 493 iface->state & IF_STA_DRORBDR) { 494 if (if_join_group(iface, &addr)) 495 return (-1); 496 } 497 498 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 499 if (nbr->state & NBR_STA_BIDIR) 500 nbr_fsm(nbr, NBR_EVT_ADJ_OK); 501 } 502 503 orig_rtr_lsa(iface->area); 504 if (iface->state & IF_STA_DR || old_state & IF_STA_DR) 505 orig_net_lsa(iface); 506 } 507 508 if_start_hello_timer(iface); 509 return (0); 510 } 511 512 int 513 if_act_reset(struct iface *iface) 514 { 515 struct nbr *nbr = NULL; 516 struct in_addr addr; 517 518 if (iface->passive) { 519 /* for an update of stub network entries */ 520 orig_rtr_lsa(iface->area); 521 return (0); 522 } 523 524 switch (iface->type) { 525 case IF_TYPE_POINTOPOINT: 526 case IF_TYPE_BROADCAST: 527 inet_aton(AllSPFRouters, &addr); 528 if (if_leave_group(iface, &addr)) { 529 log_warnx("if_act_reset: error leaving group %s, " 530 "interface %s", inet_ntoa(addr), iface->name); 531 } 532 if (iface->state & IF_STA_DRORBDR) { 533 inet_aton(AllDRouters, &addr); 534 if (if_leave_group(iface, &addr)) { 535 log_warnx("if_act_reset: " 536 "error leaving group %s, interface %s", 537 inet_ntoa(addr), iface->name); 538 } 539 } 540 break; 541 case IF_TYPE_VIRTUALLINK: 542 /* nothing */ 543 break; 544 case IF_TYPE_NBMA: 545 case IF_TYPE_POINTOMULTIPOINT: 546 log_debug("if_act_reset: type %s not supported, interface %s", 547 if_type_name(iface->type), iface->name); 548 return (-1); 549 default: 550 fatalx("if_act_reset: unknown interface type"); 551 } 552 553 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 554 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 555 log_debug("if_act_reset: error killing neighbor %s", 556 inet_ntoa(nbr->id)); 557 } 558 } 559 560 iface->dr = NULL; 561 iface->bdr = NULL; 562 563 ls_ack_list_clr(iface); 564 stop_ls_ack_tx_timer(iface); 565 if_stop_hello_timer(iface); 566 if_stop_wait_timer(iface); 567 568 /* send empty hello to tell everybody that we are going down */ 569 send_hello(iface); 570 571 return (0); 572 } 573 574 struct ctl_iface * 575 if_to_ctl(struct iface *iface) 576 { 577 static struct ctl_iface ictl; 578 struct timeval tv, now, res; 579 struct nbr *nbr; 580 581 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 582 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 583 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 584 ictl.rtr_id.s_addr = ospfe_router_id(); 585 memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area)); 586 if (iface->dr) { 587 memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id)); 588 memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr)); 589 } else { 590 bzero(&ictl.dr_id, sizeof(ictl.dr_id)); 591 bzero(&ictl.dr_addr, sizeof(ictl.dr_addr)); 592 } 593 if (iface->bdr) { 594 memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id)); 595 memcpy(&ictl.bdr_addr, &iface->bdr->addr, 596 sizeof(ictl.bdr_addr)); 597 } else { 598 bzero(&ictl.bdr_id, sizeof(ictl.bdr_id)); 599 bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr)); 600 } 601 ictl.ifindex = iface->ifindex; 602 ictl.state = iface->state; 603 ictl.mtu = iface->mtu; 604 ictl.nbr_cnt = 0; 605 ictl.adj_cnt = 0; 606 ictl.baudrate = iface->baudrate; 607 ictl.dead_interval = iface->dead_interval; 608 ictl.transmit_delay = iface->transmit_delay; 609 ictl.hello_interval = iface->hello_interval; 610 ictl.flags = iface->flags; 611 ictl.metric = iface->metric; 612 ictl.rxmt_interval = iface->rxmt_interval; 613 ictl.type = iface->type; 614 ictl.linkstate = iface->linkstate; 615 ictl.mediatype = iface->media_type; 616 ictl.priority = iface->priority; 617 ictl.passive = iface->passive; 618 ictl.auth_type = iface->auth_type; 619 ictl.auth_keyid = iface->auth_keyid; 620 621 gettimeofday(&now, NULL); 622 if (evtimer_pending(&iface->hello_timer, &tv)) { 623 timersub(&tv, &now, &res); 624 ictl.hello_timer = res.tv_sec; 625 } else 626 ictl.hello_timer = -1; 627 628 if (iface->state != IF_STA_DOWN) { 629 ictl.uptime = now.tv_sec - iface->uptime; 630 } else 631 ictl.uptime = 0; 632 633 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 634 if (nbr == iface->self) 635 continue; 636 ictl.nbr_cnt++; 637 if (nbr->state & NBR_STA_ADJFORM) 638 ictl.adj_cnt++; 639 } 640 641 return (&ictl); 642 } 643 644 /* misc */ 645 int 646 if_set_recvif(int fd, int enable) 647 { 648 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 649 sizeof(enable)) < 0) { 650 log_warn("if_set_recvif: error setting IP_RECVIF"); 651 return (-1); 652 } 653 return (0); 654 } 655 656 void 657 if_set_recvbuf(int fd) 658 { 659 int bsize; 660 661 bsize = 65535; 662 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 663 sizeof(bsize)) == -1) 664 bsize /= 2; 665 } 666 667 /* 668 * only one JOIN or DROP per interface and address is allowed so we need 669 * to keep track of what is added and removed. 670 */ 671 struct if_group_count { 672 LIST_ENTRY(if_group_count) entry; 673 struct in_addr addr; 674 unsigned int ifindex; 675 int count; 676 }; 677 678 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 679 680 int 681 if_join_group(struct iface *iface, struct in_addr *addr) 682 { 683 struct ip_mreq mreq; 684 struct if_group_count *ifg; 685 686 switch (iface->type) { 687 case IF_TYPE_POINTOPOINT: 688 case IF_TYPE_BROADCAST: 689 LIST_FOREACH(ifg, &ifglist, entry) 690 if (iface->ifindex == ifg->ifindex && 691 addr->s_addr == ifg->addr.s_addr) 692 break; 693 if (ifg == NULL) { 694 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 695 fatal("if_join_group"); 696 ifg->addr.s_addr = addr->s_addr; 697 ifg->ifindex = iface->ifindex; 698 LIST_INSERT_HEAD(&ifglist, ifg, entry); 699 } 700 701 if (ifg->count++ != 0) 702 /* already joined */ 703 return (0); 704 705 mreq.imr_multiaddr.s_addr = addr->s_addr; 706 mreq.imr_interface.s_addr = iface->addr.s_addr; 707 708 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 709 (void *)&mreq, sizeof(mreq)) < 0) { 710 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 711 "interface %s address %s", iface->name, 712 inet_ntoa(*addr)); 713 return (-1); 714 } 715 break; 716 case IF_TYPE_POINTOMULTIPOINT: 717 case IF_TYPE_VIRTUALLINK: 718 case IF_TYPE_NBMA: 719 log_debug("if_join_group: type %s not supported, interface %s", 720 if_type_name(iface->type), iface->name); 721 return (-1); 722 default: 723 fatalx("if_join_group: unknown interface type"); 724 } 725 726 return (0); 727 } 728 729 int 730 if_leave_group(struct iface *iface, struct in_addr *addr) 731 { 732 struct ip_mreq mreq; 733 struct if_group_count *ifg; 734 735 switch (iface->type) { 736 case IF_TYPE_POINTOPOINT: 737 case IF_TYPE_BROADCAST: 738 LIST_FOREACH(ifg, &ifglist, entry) 739 if (iface->ifindex == ifg->ifindex && 740 addr->s_addr == ifg->addr.s_addr) 741 break; 742 743 /* if interface is not found just try to drop membership */ 744 if (ifg && --ifg->count != 0) 745 /* others still joined */ 746 return (0); 747 748 mreq.imr_multiaddr.s_addr = addr->s_addr; 749 mreq.imr_interface.s_addr = iface->addr.s_addr; 750 751 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 752 (void *)&mreq, sizeof(mreq)) < 0) { 753 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 754 "interface %s address %s", iface->name, 755 inet_ntoa(*addr)); 756 return (-1); 757 } 758 759 if (ifg) { 760 LIST_REMOVE(ifg, entry); 761 free(ifg); 762 } 763 break; 764 case IF_TYPE_POINTOMULTIPOINT: 765 case IF_TYPE_VIRTUALLINK: 766 case IF_TYPE_NBMA: 767 log_debug("if_leave_group: type %s not supported, interface %s", 768 if_type_name(iface->type), iface->name); 769 return (-1); 770 default: 771 fatalx("if_leave_group: unknown interface type"); 772 } 773 774 return (0); 775 } 776 777 int 778 if_set_mcast(struct iface *iface) 779 { 780 switch (iface->type) { 781 case IF_TYPE_POINTOPOINT: 782 case IF_TYPE_BROADCAST: 783 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 784 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 785 log_debug("if_set_mcast: error setting " 786 "IP_MULTICAST_IF, interface %s", iface->name); 787 return (-1); 788 } 789 break; 790 case IF_TYPE_POINTOMULTIPOINT: 791 case IF_TYPE_VIRTUALLINK: 792 case IF_TYPE_NBMA: 793 log_debug("if_set_mcast: type %s not supported, interface %s", 794 if_type_name(iface->type), iface->name); 795 return (-1); 796 default: 797 fatalx("if_set_mcast: unknown interface type"); 798 } 799 800 return (0); 801 } 802 803 int 804 if_set_mcast_loop(int fd) 805 { 806 u_int8_t loop = 0; 807 808 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 809 (char *)&loop, sizeof(loop)) < 0) { 810 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 811 return (-1); 812 } 813 814 return (0); 815 } 816 817 int 818 if_set_ip_hdrincl(int fd) 819 { 820 int hincl = 1; 821 822 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) { 823 log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL"); 824 return (-1); 825 } 826 827 return (0); 828 } 829