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