1 /* $OpenBSD: interface.c,v 1.68 2010/02/16 18:20:37 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 if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) && 143 (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 144 ospfe_demote_iface(iface, 0); 145 if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 && 146 iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) 147 ospfe_demote_iface(iface, 1); 148 149 log_debug("if_fsm: event %s resulted in action %s and changing " 150 "state for interface %s from %s to %s", 151 if_event_names[event], if_action_names[iface_fsm[i].action], 152 iface->name, if_state_name(old_state), if_state_name(iface->state)); 153 154 return (ret); 155 } 156 157 struct iface * 158 if_new(struct kif *kif, struct kif_addr *ka) 159 { 160 struct iface *iface; 161 162 if ((iface = calloc(1, sizeof(*iface))) == NULL) 163 err(1, "if_new: calloc"); 164 165 iface->state = IF_STA_DOWN; 166 167 LIST_INIT(&iface->nbr_list); 168 TAILQ_INIT(&iface->ls_ack_list); 169 TAILQ_INIT(&iface->auth_md_list); 170 171 iface->crypt_seq_num = arc4random() & 0x0fffffff; 172 173 if (kif == NULL) { 174 iface->type = IF_TYPE_VIRTUALLINK; 175 snprintf(iface->name, sizeof(iface->name), "vlink%d", 176 vlink_cnt++); 177 iface->flags |= IFF_UP; 178 iface->mtu = IP_MSS; 179 return (iface); 180 } 181 182 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 183 184 /* get type */ 185 if (kif->flags & IFF_POINTOPOINT) 186 iface->type = IF_TYPE_POINTOPOINT; 187 if (kif->flags & IFF_BROADCAST && 188 kif->flags & IFF_MULTICAST) 189 iface->type = IF_TYPE_BROADCAST; 190 if (kif->flags & IFF_LOOPBACK) { 191 iface->type = IF_TYPE_POINTOPOINT; 192 iface->state = IF_STA_LOOPBACK; 193 } 194 195 /* get mtu, index and flags */ 196 iface->mtu = kif->mtu; 197 iface->ifindex = kif->ifindex; 198 iface->flags = kif->flags; 199 iface->linkstate = kif->link_state; 200 iface->media_type = kif->media_type; 201 iface->baudrate = kif->baudrate; 202 203 /* set address, mask and p2p addr */ 204 iface->addr = ka->addr; 205 iface->mask = ka->mask; 206 if (kif->flags & IFF_POINTOPOINT) { 207 iface->dst = ka->dstbrd; 208 } 209 210 return (iface); 211 } 212 213 void 214 if_del(struct iface *iface) 215 { 216 struct nbr *nbr = NULL; 217 218 /* revert the demotion when the interface is deleted */ 219 if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 220 ospfe_demote_iface(iface, 1); 221 222 /* clear lists etc */ 223 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 224 nbr_del(nbr); 225 226 if (evtimer_pending(&iface->hello_timer, NULL)) 227 evtimer_del(&iface->hello_timer); 228 if (evtimer_pending(&iface->wait_timer, NULL)) 229 evtimer_del(&iface->wait_timer); 230 if (evtimer_pending(&iface->lsack_tx_timer, NULL)) 231 evtimer_del(&iface->lsack_tx_timer); 232 233 ls_ack_list_clr(iface); 234 md_list_clr(&iface->auth_md_list); 235 free(iface); 236 } 237 238 void 239 if_init(struct ospfd_conf *xconf, struct iface *iface) 240 { 241 struct ifreq ifr; 242 u_int rdomain; 243 244 /* init the dummy local neighbor */ 245 iface->self = nbr_new(ospfe_router_id(), iface, 1); 246 247 /* set event handlers for interface */ 248 evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface); 249 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 250 evtimer_set(&iface->wait_timer, if_wait_timer, iface); 251 252 iface->fd = xconf->ospf_socket; 253 254 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); 255 if (ioctl(iface->fd, SIOCGIFRTABLEID, (caddr_t)&ifr) == -1) 256 rdomain = 0; 257 else { 258 rdomain = ifr.ifr_rdomainid; 259 if (setsockopt(iface->fd, IPPROTO_IP, SO_RDOMAIN, 260 &rdomain, sizeof(rdomain)) == -1) 261 fatal("failed to set rdomain"); 262 } 263 if (rdomain != xconf->rdomain) 264 fatalx("interface rdomain mismatch"); 265 266 ospfe_demote_iface(iface, 0); 267 } 268 269 /* timers */ 270 /* ARGSUSED */ 271 void 272 if_hello_timer(int fd, short event, void *arg) 273 { 274 struct iface *iface = arg; 275 struct timeval tv; 276 277 send_hello(iface); 278 279 /* reschedule hello_timer */ 280 timerclear(&tv); 281 if (iface->dead_interval == FAST_RTR_DEAD_TIME) 282 tv.tv_usec = iface->fast_hello_interval * 1000; 283 else 284 tv.tv_sec = iface->hello_interval; 285 if (evtimer_add(&iface->hello_timer, &tv) == -1) 286 fatal("if_hello_timer"); 287 } 288 289 void 290 if_start_hello_timer(struct iface *iface) 291 { 292 struct timeval tv; 293 294 timerclear(&tv); 295 if (evtimer_add(&iface->hello_timer, &tv) == -1) 296 fatal("if_start_hello_timer"); 297 } 298 299 void 300 if_stop_hello_timer(struct iface *iface) 301 { 302 if (evtimer_del(&iface->hello_timer) == -1) 303 fatal("if_stop_hello_timer"); 304 } 305 306 /* ARGSUSED */ 307 void 308 if_wait_timer(int fd, short event, void *arg) 309 { 310 struct iface *iface = arg; 311 312 if_fsm(iface, IF_EVT_WTIMER); 313 } 314 315 void 316 if_start_wait_timer(struct iface *iface) 317 { 318 struct timeval tv; 319 320 timerclear(&tv); 321 tv.tv_sec = iface->dead_interval; 322 if (evtimer_add(&iface->wait_timer, &tv) == -1) 323 fatal("if_start_wait_timer"); 324 } 325 326 void 327 if_stop_wait_timer(struct iface *iface) 328 { 329 if (evtimer_del(&iface->wait_timer) == -1) 330 fatal("if_stop_wait_timer"); 331 } 332 333 /* actions */ 334 int 335 if_act_start(struct iface *iface) 336 { 337 struct in_addr addr; 338 struct timeval now; 339 340 if (!((iface->flags & IFF_UP) && 341 (LINK_STATE_IS_UP(iface->linkstate) || 342 (iface->linkstate == LINK_STATE_UNKNOWN && 343 iface->media_type != IFT_CARP)))) 344 return (0); 345 346 if (iface->media_type == IFT_CARP && iface->passive == 0) { 347 /* force passive mode on carp interfaces */ 348 log_warnx("if_act_start: forcing interface %s to passive", 349 iface->name); 350 iface->passive = 1; 351 } 352 353 if (iface->passive) { 354 /* for an update of stub network entries */ 355 orig_rtr_lsa(iface->area); 356 return (0); 357 } 358 359 gettimeofday(&now, NULL); 360 iface->uptime = now.tv_sec; 361 362 switch (iface->type) { 363 case IF_TYPE_POINTOPOINT: 364 inet_aton(AllSPFRouters, &addr); 365 if (if_join_group(iface, &addr)) 366 return (-1); 367 iface->state = IF_STA_POINTTOPOINT; 368 break; 369 case IF_TYPE_VIRTUALLINK: 370 iface->state = IF_STA_POINTTOPOINT; 371 break; 372 case IF_TYPE_POINTOMULTIPOINT: 373 case IF_TYPE_NBMA: 374 log_debug("if_act_start: type %s not supported, interface %s", 375 if_type_name(iface->type), iface->name); 376 return (-1); 377 case IF_TYPE_BROADCAST: 378 inet_aton(AllSPFRouters, &addr); 379 if (if_join_group(iface, &addr)) 380 return (-1); 381 if (iface->priority == 0) { 382 iface->state = IF_STA_DROTHER; 383 } else { 384 iface->state = IF_STA_WAITING; 385 if_start_wait_timer(iface); 386 } 387 break; 388 default: 389 fatalx("if_act_start: unknown interface type"); 390 } 391 392 /* hello timer needs to be started in any case */ 393 if_start_hello_timer(iface); 394 return (0); 395 } 396 397 struct nbr * 398 if_elect(struct nbr *a, struct nbr *b) 399 { 400 if (a->priority > b->priority) 401 return (a); 402 if (a->priority < b->priority) 403 return (b); 404 if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr)) 405 return (a); 406 return (b); 407 } 408 409 int 410 if_act_elect(struct iface *iface) 411 { 412 struct in_addr addr; 413 struct nbr *nbr, *bdr = NULL, *dr = NULL; 414 int round = 0; 415 int changed = 0; 416 int old_state; 417 char b1[16], b2[16], b3[16], b4[16]; 418 419 start: 420 /* elect backup designated router */ 421 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 422 if (nbr->priority == 0 || nbr == dr || /* not electable */ 423 nbr->state & NBR_STA_PRELIM || /* not available */ 424 nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */ 425 continue; 426 if (bdr != NULL) { 427 /* 428 * routers announcing themselves as BDR have higher 429 * precedence over those routers announcing a 430 * different BDR. 431 */ 432 if (nbr->bdr.s_addr == nbr->addr.s_addr) { 433 if (bdr->bdr.s_addr == bdr->addr.s_addr) 434 bdr = if_elect(bdr, nbr); 435 else 436 bdr = nbr; 437 } else if (bdr->bdr.s_addr != bdr->addr.s_addr) 438 bdr = if_elect(bdr, nbr); 439 } else 440 bdr = nbr; 441 } 442 443 /* elect designated router */ 444 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 445 if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM || 446 (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr)) 447 /* only DR may be elected check priority too */ 448 continue; 449 if (dr == NULL) 450 dr = nbr; 451 else 452 dr = if_elect(dr, nbr); 453 } 454 455 if (dr == NULL) { 456 /* no designated router found use backup DR */ 457 dr = bdr; 458 bdr = NULL; 459 } 460 461 /* 462 * if we are involved in the election (e.g. new DR or no 463 * longer BDR) redo the election 464 */ 465 if (round == 0 && 466 ((iface->self == dr && iface->self != iface->dr) || 467 (iface->self != dr && iface->self == iface->dr) || 468 (iface->self == bdr && iface->self != iface->bdr) || 469 (iface->self != bdr && iface->self == iface->bdr))) { 470 /* 471 * Reset announced DR/BDR to calculated one, so 472 * that we may get elected in the second round. 473 * This is needed to drop from a DR to a BDR. 474 */ 475 iface->self->dr.s_addr = dr->addr.s_addr; 476 if (bdr) 477 iface->self->bdr.s_addr = bdr->addr.s_addr; 478 round = 1; 479 goto start; 480 } 481 482 log_debug("if_act_elect: interface %s old dr %s new dr %s, " 483 "old bdr %s new bdr %s", iface->name, 484 iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) : 485 "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none", 486 iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) : 487 "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) : 488 "none"); 489 490 /* 491 * After the second round still DR or BDR change state to DR or BDR, 492 * etc. 493 */ 494 old_state = iface->state; 495 if (dr == iface->self) 496 iface->state = IF_STA_DR; 497 else if (bdr == iface->self) 498 iface->state = IF_STA_BACKUP; 499 else 500 iface->state = IF_STA_DROTHER; 501 502 /* TODO if iface is NBMA send all non eligible neighbors event Start */ 503 504 /* 505 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way 506 */ 507 if (iface->dr != dr || iface->bdr != bdr) 508 changed = 1; 509 510 iface->dr = dr; 511 iface->bdr = bdr; 512 513 if (changed) { 514 inet_aton(AllDRouters, &addr); 515 if (old_state & IF_STA_DRORBDR && 516 (iface->state & IF_STA_DRORBDR) == 0) { 517 if (if_leave_group(iface, &addr)) 518 return (-1); 519 } else if ((old_state & IF_STA_DRORBDR) == 0 && 520 iface->state & IF_STA_DRORBDR) { 521 if (if_join_group(iface, &addr)) 522 return (-1); 523 } 524 525 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 526 if (nbr->state & NBR_STA_BIDIR) 527 nbr_fsm(nbr, NBR_EVT_ADJ_OK); 528 } 529 530 orig_rtr_lsa(iface->area); 531 if (iface->state & IF_STA_DR || old_state & IF_STA_DR) 532 orig_net_lsa(iface); 533 } 534 535 if_start_hello_timer(iface); 536 return (0); 537 } 538 539 int 540 if_act_reset(struct iface *iface) 541 { 542 struct nbr *nbr = NULL; 543 struct in_addr addr; 544 545 if (iface->passive) { 546 /* for an update of stub network entries */ 547 orig_rtr_lsa(iface->area); 548 return (0); 549 } 550 551 switch (iface->type) { 552 case IF_TYPE_POINTOPOINT: 553 case IF_TYPE_BROADCAST: 554 /* try to cleanup */ 555 inet_aton(AllSPFRouters, &addr); 556 if_leave_group(iface, &addr); 557 if (iface->state & IF_STA_DRORBDR) { 558 inet_aton(AllDRouters, &addr); 559 if_leave_group(iface, &addr); 560 } 561 break; 562 case IF_TYPE_VIRTUALLINK: 563 /* nothing */ 564 break; 565 case IF_TYPE_NBMA: 566 case IF_TYPE_POINTOMULTIPOINT: 567 log_debug("if_act_reset: type %s not supported, interface %s", 568 if_type_name(iface->type), iface->name); 569 return (-1); 570 default: 571 fatalx("if_act_reset: unknown interface type"); 572 } 573 574 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 575 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 576 log_debug("if_act_reset: error killing neighbor %s", 577 inet_ntoa(nbr->id)); 578 } 579 } 580 581 iface->dr = NULL; 582 iface->bdr = NULL; 583 584 ls_ack_list_clr(iface); 585 stop_ls_ack_tx_timer(iface); 586 if_stop_hello_timer(iface); 587 if_stop_wait_timer(iface); 588 589 /* send empty hello to tell everybody that we are going down */ 590 send_hello(iface); 591 592 return (0); 593 } 594 595 struct ctl_iface * 596 if_to_ctl(struct iface *iface) 597 { 598 static struct ctl_iface ictl; 599 struct timeval tv, now, res; 600 struct nbr *nbr; 601 602 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 603 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 604 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 605 ictl.rtr_id.s_addr = ospfe_router_id(); 606 memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area)); 607 if (iface->dr) { 608 memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id)); 609 memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr)); 610 } else { 611 bzero(&ictl.dr_id, sizeof(ictl.dr_id)); 612 bzero(&ictl.dr_addr, sizeof(ictl.dr_addr)); 613 } 614 if (iface->bdr) { 615 memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id)); 616 memcpy(&ictl.bdr_addr, &iface->bdr->addr, 617 sizeof(ictl.bdr_addr)); 618 } else { 619 bzero(&ictl.bdr_id, sizeof(ictl.bdr_id)); 620 bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr)); 621 } 622 ictl.ifindex = iface->ifindex; 623 ictl.state = iface->state; 624 ictl.mtu = iface->mtu; 625 ictl.nbr_cnt = 0; 626 ictl.adj_cnt = 0; 627 ictl.baudrate = iface->baudrate; 628 ictl.dead_interval = iface->dead_interval; 629 ictl.fast_hello_interval = iface->fast_hello_interval; 630 ictl.transmit_delay = iface->transmit_delay; 631 ictl.hello_interval = iface->hello_interval; 632 ictl.flags = iface->flags; 633 ictl.metric = iface->metric; 634 ictl.rxmt_interval = iface->rxmt_interval; 635 ictl.type = iface->type; 636 ictl.linkstate = iface->linkstate; 637 ictl.mediatype = iface->media_type; 638 ictl.priority = iface->priority; 639 ictl.passive = iface->passive; 640 ictl.auth_type = iface->auth_type; 641 ictl.auth_keyid = iface->auth_keyid; 642 643 gettimeofday(&now, NULL); 644 if (evtimer_pending(&iface->hello_timer, &tv)) { 645 timersub(&tv, &now, &res); 646 ictl.hello_timer = res; 647 } else { 648 ictl.hello_timer.tv_sec = -1; 649 } 650 651 if (iface->state != IF_STA_DOWN) { 652 ictl.uptime = now.tv_sec - iface->uptime; 653 } else 654 ictl.uptime = 0; 655 656 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 657 if (nbr == iface->self) 658 continue; 659 ictl.nbr_cnt++; 660 if (nbr->state & NBR_STA_ADJFORM) 661 ictl.adj_cnt++; 662 } 663 664 return (&ictl); 665 } 666 667 /* misc */ 668 int 669 if_set_recvif(int fd, int enable) 670 { 671 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 672 sizeof(enable)) < 0) { 673 log_warn("if_set_recvif: error setting IP_RECVIF"); 674 return (-1); 675 } 676 return (0); 677 } 678 679 void 680 if_set_sockbuf(int fd) 681 { 682 int bsize; 683 684 bsize = 65535; 685 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 686 sizeof(bsize)) == -1) 687 bsize /= 2; 688 689 if (bsize != 65535) 690 log_warnx("if_set_sockbuf: recvbuf size only %d", bsize); 691 692 bsize = 65535; 693 while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, 694 sizeof(bsize)) == -1) 695 bsize /= 2; 696 697 if (bsize != 65535) 698 log_warnx("if_set_sockbuf: sendbuf size only %d", bsize); 699 } 700 701 /* 702 * only one JOIN or DROP per interface and address is allowed so we need 703 * to keep track of what is added and removed. 704 */ 705 struct if_group_count { 706 LIST_ENTRY(if_group_count) entry; 707 struct in_addr addr; 708 unsigned int ifindex; 709 int count; 710 }; 711 712 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 713 714 int 715 if_join_group(struct iface *iface, struct in_addr *addr) 716 { 717 struct ip_mreq mreq; 718 struct if_group_count *ifg; 719 720 switch (iface->type) { 721 case IF_TYPE_POINTOPOINT: 722 case IF_TYPE_BROADCAST: 723 LIST_FOREACH(ifg, &ifglist, entry) 724 if (iface->ifindex == ifg->ifindex && 725 addr->s_addr == ifg->addr.s_addr) 726 break; 727 if (ifg == NULL) { 728 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 729 fatal("if_join_group"); 730 ifg->addr.s_addr = addr->s_addr; 731 ifg->ifindex = iface->ifindex; 732 LIST_INSERT_HEAD(&ifglist, ifg, entry); 733 } 734 735 if (ifg->count++ != 0) 736 /* already joined */ 737 return (0); 738 739 mreq.imr_multiaddr.s_addr = addr->s_addr; 740 mreq.imr_interface.s_addr = iface->addr.s_addr; 741 742 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 743 (void *)&mreq, sizeof(mreq)) < 0) { 744 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 745 "interface %s address %s", iface->name, 746 inet_ntoa(*addr)); 747 return (-1); 748 } 749 break; 750 case IF_TYPE_POINTOMULTIPOINT: 751 case IF_TYPE_VIRTUALLINK: 752 case IF_TYPE_NBMA: 753 log_debug("if_join_group: type %s not supported, interface %s", 754 if_type_name(iface->type), iface->name); 755 return (-1); 756 default: 757 fatalx("if_join_group: unknown interface type"); 758 } 759 760 return (0); 761 } 762 763 int 764 if_leave_group(struct iface *iface, struct in_addr *addr) 765 { 766 struct ip_mreq mreq; 767 struct if_group_count *ifg; 768 769 switch (iface->type) { 770 case IF_TYPE_POINTOPOINT: 771 case IF_TYPE_BROADCAST: 772 LIST_FOREACH(ifg, &ifglist, entry) 773 if (iface->ifindex == ifg->ifindex && 774 addr->s_addr == ifg->addr.s_addr) 775 break; 776 777 /* if interface is not found just try to drop membership */ 778 if (ifg) { 779 if (--ifg->count != 0) 780 /* others still joined */ 781 return (0); 782 783 LIST_REMOVE(ifg, entry); 784 free(ifg); 785 } 786 787 mreq.imr_multiaddr.s_addr = addr->s_addr; 788 mreq.imr_interface.s_addr = iface->addr.s_addr; 789 790 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 791 (void *)&mreq, sizeof(mreq)) < 0) { 792 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 793 "interface %s address %s", iface->name, 794 inet_ntoa(*addr)); 795 return (-1); 796 } 797 break; 798 case IF_TYPE_POINTOMULTIPOINT: 799 case IF_TYPE_VIRTUALLINK: 800 case IF_TYPE_NBMA: 801 log_debug("if_leave_group: type %s not supported, interface %s", 802 if_type_name(iface->type), iface->name); 803 return (-1); 804 default: 805 fatalx("if_leave_group: unknown interface type"); 806 } 807 808 return (0); 809 } 810 811 int 812 if_set_mcast(struct iface *iface) 813 { 814 switch (iface->type) { 815 case IF_TYPE_POINTOPOINT: 816 case IF_TYPE_BROADCAST: 817 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 818 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 819 log_warn("if_set_mcast: error setting " 820 "IP_MULTICAST_IF, interface %s", iface->name); 821 return (-1); 822 } 823 break; 824 case IF_TYPE_POINTOMULTIPOINT: 825 case IF_TYPE_VIRTUALLINK: 826 case IF_TYPE_NBMA: 827 log_debug("if_set_mcast: type %s not supported, interface %s", 828 if_type_name(iface->type), iface->name); 829 return (-1); 830 default: 831 fatalx("if_set_mcast: unknown interface type"); 832 } 833 834 return (0); 835 } 836 837 int 838 if_set_mcast_loop(int fd) 839 { 840 u_int8_t loop = 0; 841 842 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 843 (char *)&loop, sizeof(loop)) < 0) { 844 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 845 return (-1); 846 } 847 848 return (0); 849 } 850 851 int 852 if_set_ip_hdrincl(int fd) 853 { 854 int hincl = 1; 855 856 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) { 857 log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL"); 858 return (-1); 859 } 860 861 return (0); 862 } 863