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