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