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