1 /* $OpenBSD: neighbor.c,v 1.34 2007/01/24 14:08:28 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 28 #include <ctype.h> 29 #include <err.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <event.h> 34 35 #include "ospfd.h" 36 #include "ospf.h" 37 #include "ospfe.h" 38 #include "log.h" 39 #include "rde.h" 40 41 int nbr_adj_ok(struct nbr *); 42 43 LIST_HEAD(nbr_head, nbr); 44 45 struct nbr_table { 46 struct nbr_head *hashtbl; 47 u_int32_t hashmask; 48 } nbrtable; 49 50 #define NBR_HASH(x) \ 51 &nbrtable.hashtbl[(x) & nbrtable.hashmask] 52 53 u_int32_t peercnt = NBR_CNTSTART; 54 55 struct { 56 int state; 57 enum nbr_event event; 58 enum nbr_action action; 59 int new_state; 60 } nbr_fsm_tbl[] = { 61 /* current state event that happened action to take resulting state */ 62 {NBR_STA_ACTIVE, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, 0}, 63 {NBR_STA_BIDIR, NBR_EVT_2_WAY_RCVD, NBR_ACT_NOTHING, 0}, 64 {NBR_STA_INIT, NBR_EVT_1_WAY_RCVD, NBR_ACT_NOTHING, 0}, 65 {NBR_STA_DOWN, NBR_EVT_HELLO_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_INIT}, 66 {NBR_STA_ATTEMPT, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, NBR_STA_INIT}, 67 {NBR_STA_INIT, NBR_EVT_2_WAY_RCVD, NBR_ACT_EVAL, 0}, 68 {NBR_STA_XSTRT, NBR_EVT_NEG_DONE, NBR_ACT_SNAP, NBR_STA_SNAP}, 69 {NBR_STA_SNAP, NBR_EVT_SNAP_DONE, NBR_ACT_SNAP_DONE, NBR_STA_XCHNG}, 70 {NBR_STA_XCHNG, NBR_EVT_XCHNG_DONE, NBR_ACT_XCHNG_DONE, 0}, 71 {NBR_STA_LOAD, NBR_EVT_LOAD_DONE, NBR_ACT_NOTHING, NBR_STA_FULL}, 72 {NBR_STA_2_WAY, NBR_EVT_ADJ_OK, NBR_ACT_EVAL, 0}, 73 {NBR_STA_ADJFORM, NBR_EVT_ADJ_OK, NBR_ACT_ADJ_OK, 0}, 74 {NBR_STA_PRELIM, NBR_EVT_ADJ_OK, NBR_ACT_HELLO_CHK, 0}, 75 {NBR_STA_ADJFORM, NBR_EVT_ADJTMOUT, NBR_ACT_RESTRT_DD, 0}, 76 {NBR_STA_FLOOD, NBR_EVT_SEQ_NUM_MIS, NBR_ACT_RESTRT_DD, NBR_STA_XSTRT}, 77 {NBR_STA_FLOOD, NBR_EVT_BAD_LS_REQ, NBR_ACT_RESTRT_DD, NBR_STA_XSTRT}, 78 {NBR_STA_ANY, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN}, 79 {NBR_STA_ANY, NBR_EVT_LL_DOWN, NBR_ACT_DEL, NBR_STA_DOWN}, 80 {NBR_STA_ANY, NBR_EVT_ITIMER, NBR_ACT_DEL, NBR_STA_DOWN}, 81 {NBR_STA_BIDIR, NBR_EVT_1_WAY_RCVD, NBR_ACT_CLR_LST, NBR_STA_INIT}, 82 {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0}, 83 }; 84 85 const char * const nbr_event_names[] = { 86 "NOTHING", 87 "HELLO_RECEIVED", 88 "2_WAY_RECEIVED", 89 "NEGOTIATION_DONE", 90 "SNAPSHOT_DONE", 91 "EXCHANGE_DONE", 92 "BAD_LS_REQ", 93 "LOADING_DONE", 94 "ADJ_OK", 95 "SEQ_NUM_MISMATCH", 96 "1_WAY_RECEIVED", 97 "KILL_NBR", 98 "INACTIVITY_TIMER", 99 "LL_DOWN", 100 "ADJ_TIMEOUT" 101 }; 102 103 const char * const nbr_action_names[] = { 104 "NOTHING", 105 "RESET_INACTIVITY_TIMER", 106 "START_INACTIVITY_TIMER", 107 "EVAL", 108 "SNAPSHOT", 109 "SNAPSHOT_DONE", 110 "EXCHANGE_DONE", 111 "ADJ_OK", 112 "RESET_DD", 113 "DELETE", 114 "CLEAR_LISTS" 115 }; 116 117 int 118 nbr_fsm(struct nbr *nbr, enum nbr_event event) 119 { 120 struct timeval now; 121 int old_state; 122 int new_state = 0; 123 int i, ret = 0; 124 125 if (nbr == nbr->iface->self) 126 return (0); 127 128 old_state = nbr->state; 129 for (i = 0; nbr_fsm_tbl[i].state != -1; i++) 130 if ((nbr_fsm_tbl[i].state & old_state) && 131 (nbr_fsm_tbl[i].event == event)) { 132 new_state = nbr_fsm_tbl[i].new_state; 133 break; 134 } 135 136 if (nbr_fsm_tbl[i].state == -1) { 137 /* event outside of the defined fsm, ignore it. */ 138 log_warnx("nbr_fsm: neighbor ID %s, " 139 "event %s not expected in state %s", 140 inet_ntoa(nbr->id), nbr_event_names[event], 141 nbr_state_name(old_state)); 142 return (0); 143 } 144 145 switch (nbr_fsm_tbl[i].action) { 146 case NBR_ACT_RST_ITIMER: 147 ret = nbr_act_reset_itimer(nbr); 148 break; 149 case NBR_ACT_STRT_ITIMER: 150 ret = nbr_act_start_itimer(nbr); 151 break; 152 case NBR_ACT_EVAL: 153 ret = nbr_act_eval(nbr); 154 break; 155 case NBR_ACT_SNAP: 156 ret = nbr_act_snapshot(nbr); 157 break; 158 case NBR_ACT_SNAP_DONE: 159 /* start db exchange */ 160 start_db_tx_timer(nbr); 161 break; 162 case NBR_ACT_XCHNG_DONE: 163 ret = nbr_act_exchange_done(nbr); 164 break; 165 case NBR_ACT_ADJ_OK: 166 ret = nbr_act_adj_ok(nbr); 167 break; 168 case NBR_ACT_RESTRT_DD: 169 ret = nbr_act_restart_dd(nbr); 170 break; 171 case NBR_ACT_DEL: 172 ret = nbr_act_delete(nbr); 173 break; 174 case NBR_ACT_CLR_LST: 175 ret = nbr_act_clear_lists(nbr); 176 break; 177 case NBR_ACT_HELLO_CHK: 178 ret = nbr_act_hello_check(nbr); 179 break; 180 case NBR_ACT_NOTHING: 181 /* do nothing */ 182 break; 183 } 184 185 if (ret) { 186 log_warnx("nbr_fsm: error changing state for neighbor ID %s, " 187 "event %s, state %s", inet_ntoa(nbr->id), 188 nbr_event_names[event], nbr_state_name(old_state)); 189 return (-1); 190 } 191 192 if (new_state != 0) 193 nbr->state = new_state; 194 195 if (old_state != nbr->state) { 196 nbr->stats.sta_chng++; 197 /* state change inform RDE */ 198 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE, 199 nbr->peerid, 0, &new_state, sizeof(new_state)); 200 201 if (old_state & NBR_STA_FULL || nbr->state & NBR_STA_FULL) { 202 /* 203 * neighbor changed from/to FULL 204 * originate new rtr and net LSA 205 */ 206 area_track(nbr->iface->area, nbr->state); 207 orig_rtr_lsa(nbr->iface->area); 208 if (nbr->iface->state & IF_STA_DR) 209 orig_net_lsa(nbr->iface); 210 211 gettimeofday(&now, NULL); 212 nbr->uptime = now.tv_sec; 213 } 214 215 /* bidirectional communication lost */ 216 if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM) 217 if_fsm(nbr->iface, IF_EVT_NBR_CHNG); 218 219 log_debug("nbr_fsm: event %s resulted in action %s and " 220 "changing state for neighbor ID %s from %s to %s", 221 nbr_event_names[event], 222 nbr_action_names[nbr_fsm_tbl[i].action], 223 inet_ntoa(nbr->id), nbr_state_name(old_state), 224 nbr_state_name(nbr->state)); 225 226 if (nbr->iface->type == IF_TYPE_VIRTUALLINK) { 227 orig_rtr_lsa(nbr->iface->area); 228 } 229 } 230 231 return (ret); 232 } 233 234 void 235 nbr_init(u_int32_t hashsize) 236 { 237 struct nbr_head *head; 238 struct nbr *nbr; 239 u_int32_t hs, i; 240 241 for (hs = 1; hs < hashsize; hs <<= 1) 242 ; 243 nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head)); 244 if (nbrtable.hashtbl == NULL) 245 fatal("nbr_init"); 246 247 for (i = 0; i < hs; i++) 248 LIST_INIT(&nbrtable.hashtbl[i]); 249 250 nbrtable.hashmask = hs - 1; 251 252 /* allocate a dummy neighbor used for self originated AS ext routes */ 253 if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 254 fatal("nbr_init"); 255 256 nbr->id.s_addr = ospfe_router_id(); 257 nbr->state = NBR_STA_DOWN; 258 nbr->peerid = NBR_IDSELF; 259 head = NBR_HASH(nbr->peerid); 260 LIST_INSERT_HEAD(head, nbr, hash); 261 262 TAILQ_INIT(&nbr->ls_retrans_list); 263 TAILQ_INIT(&nbr->db_sum_list); 264 TAILQ_INIT(&nbr->ls_req_list); 265 } 266 267 struct nbr * 268 nbr_new(u_int32_t nbr_id, struct iface *iface, int self) 269 { 270 struct nbr_head *head; 271 struct nbr *nbr; 272 struct rde_nbr rn; 273 274 if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 275 fatal("nbr_new"); 276 277 nbr->state = NBR_STA_DOWN; 278 nbr->master = 1; 279 nbr->dd_seq_num = arc4random(); /* RFC: some unique value */ 280 nbr->id.s_addr = nbr_id; 281 282 /* get next unused peerid */ 283 while (nbr_find_peerid(++peercnt)) 284 ; 285 nbr->peerid = peercnt; 286 head = NBR_HASH(nbr->peerid); 287 LIST_INSERT_HEAD(head, nbr, hash); 288 289 /* add to peer list */ 290 nbr->iface = iface; 291 LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry); 292 293 TAILQ_INIT(&nbr->ls_retrans_list); 294 TAILQ_INIT(&nbr->db_sum_list); 295 TAILQ_INIT(&nbr->ls_req_list); 296 297 nbr->ls_req = NULL; 298 299 if (self) { 300 nbr->state = NBR_STA_FULL; 301 nbr->addr.s_addr = iface->addr.s_addr; 302 nbr->priority = iface->priority; 303 } 304 305 /* set event structures */ 306 evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr); 307 evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr); 308 evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr); 309 evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr); 310 evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr); 311 312 bzero(&rn, sizeof(rn)); 313 rn.id.s_addr = nbr->id.s_addr; 314 rn.area_id.s_addr = nbr->iface->area->id.s_addr; 315 rn.state = nbr->state; 316 rn.self = self; 317 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn, 318 sizeof(rn)); 319 320 return (nbr); 321 } 322 323 void 324 nbr_del(struct nbr *nbr) 325 { 326 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0); 327 328 if (evtimer_pending(&nbr->inactivity_timer, NULL)) 329 evtimer_del(&nbr->inactivity_timer); 330 if (evtimer_pending(&nbr->db_tx_timer, NULL)) 331 evtimer_del(&nbr->db_tx_timer); 332 if (evtimer_pending(&nbr->lsreq_tx_timer, NULL)) 333 evtimer_del(&nbr->lsreq_tx_timer); 334 if (evtimer_pending(&nbr->ls_retrans_timer, NULL)) 335 evtimer_del(&nbr->ls_retrans_timer); 336 if (evtimer_pending(&nbr->adj_timer, NULL)) 337 evtimer_del(&nbr->adj_timer); 338 339 /* clear lists */ 340 ls_retrans_list_clr(nbr); 341 db_sum_list_clr(nbr); 342 ls_req_list_clr(nbr); 343 344 LIST_REMOVE(nbr, entry); 345 LIST_REMOVE(nbr, hash); 346 347 free(nbr); 348 } 349 350 struct nbr * 351 nbr_find_peerid(u_int32_t peerid) 352 { 353 struct nbr_head *head; 354 struct nbr *nbr; 355 356 head = NBR_HASH(peerid); 357 358 LIST_FOREACH(nbr, head, hash) { 359 if (nbr->peerid == peerid) 360 return (nbr); 361 } 362 363 return (NULL); 364 } 365 366 struct nbr * 367 nbr_find_id(struct iface *iface, u_int32_t rtr_id) 368 { 369 struct nbr *nbr = NULL; 370 371 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 372 if (nbr->id.s_addr == rtr_id) 373 return (nbr); 374 } 375 376 return (NULL); 377 } 378 379 /* timers */ 380 /* ARGSUSED */ 381 void 382 nbr_itimer(int fd, short event, void *arg) 383 { 384 struct nbr *nbr = arg; 385 386 if (nbr->state == NBR_STA_DOWN) 387 nbr_del(nbr); 388 else 389 nbr_fsm(nbr, NBR_EVT_ITIMER); 390 } 391 392 void 393 nbr_start_itimer(struct nbr *nbr) 394 { 395 struct timeval tv; 396 397 timerclear(&tv); 398 tv.tv_sec = nbr->iface->dead_interval; 399 400 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1) 401 fatal("nbr_start_itimer"); 402 } 403 404 void 405 nbr_stop_itimer(struct nbr *nbr) 406 { 407 if (evtimer_del(&nbr->inactivity_timer) == -1) 408 fatal("nbr_stop_itimer"); 409 } 410 411 void 412 nbr_reset_itimer(struct nbr *nbr) 413 { 414 struct timeval tv; 415 416 timerclear(&tv); 417 tv.tv_sec = nbr->iface->dead_interval; 418 419 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1) 420 fatal("nbr_reset_itimer"); 421 } 422 423 /* ARGSUSED */ 424 void 425 nbr_adj_timer(int fd, short event, void *arg) 426 { 427 struct nbr *nbr = arg; 428 429 if (nbr->state == NBR_STA_2_WAY) 430 return ; 431 432 if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) { 433 log_warnx("nbr_adj_timer: failed to form adjacency with %s", 434 inet_ntoa(nbr->id)); 435 nbr_fsm(nbr, NBR_EVT_ADJTMOUT); 436 } 437 } 438 439 void 440 nbr_start_adj_timer(struct nbr *nbr) 441 { 442 struct timeval tv; 443 444 timerclear(&tv); 445 tv.tv_sec = DEFAULT_ADJ_TMOUT; 446 447 if (evtimer_add(&nbr->adj_timer, &tv) == -1) 448 fatal("nbr_start_adj_timer"); 449 } 450 451 /* actions */ 452 int 453 nbr_act_reset_itimer(struct nbr *nbr) 454 { 455 nbr_reset_itimer(nbr); 456 457 return (0); 458 } 459 460 int 461 nbr_act_start_itimer(struct nbr *nbr) 462 { 463 nbr_start_itimer(nbr); 464 465 return (0); 466 } 467 468 int 469 nbr_adj_ok(struct nbr *nbr) 470 { 471 struct iface *iface = nbr->iface; 472 473 switch (iface->type) { 474 case IF_TYPE_POINTOPOINT: 475 case IF_TYPE_VIRTUALLINK: 476 case IF_TYPE_POINTOMULTIPOINT: 477 /* always ok */ 478 break; 479 case IF_TYPE_BROADCAST: 480 case IF_TYPE_NBMA: 481 /* 482 * if neighbor is dr, bdr or router self is dr or bdr 483 * start forming adjacency 484 */ 485 if (iface->dr == nbr || iface->bdr == nbr || 486 iface->state & IF_STA_DRORBDR) 487 break; 488 return (0); 489 default: 490 fatalx("nbr_act_ok: unknown interface type"); 491 } 492 return (1); 493 } 494 495 int 496 nbr_act_eval(struct nbr *nbr) 497 { 498 if (!nbr_adj_ok(nbr)) { 499 nbr->state = NBR_STA_2_WAY; 500 return (0); 501 } 502 503 nbr->state = NBR_STA_XSTRT; 504 nbr->master = 1; 505 nbr->dd_seq_num++; /* as per RFC */ 506 nbr->dd_pending = 0; 507 /* initial db negotiation */ 508 start_db_tx_timer(nbr); 509 510 nbr_start_adj_timer(nbr); 511 512 return (0); 513 } 514 515 int 516 nbr_act_snapshot(struct nbr *nbr) 517 { 518 stop_db_tx_timer(nbr); 519 520 ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0); 521 522 return (0); 523 } 524 525 int 526 nbr_act_exchange_done(struct nbr *nbr) 527 { 528 if (nbr->master) 529 stop_db_tx_timer(nbr); 530 531 if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG && 532 nbr->dd_pending == 0) { 533 nbr->state = NBR_STA_FULL; 534 return (0); 535 } 536 537 nbr->state = NBR_STA_LOAD; 538 539 if (!ls_req_list_empty(nbr)) 540 start_ls_req_tx_timer(nbr); 541 542 return (0); 543 } 544 545 int 546 nbr_act_adj_ok(struct nbr *nbr) 547 { 548 if (nbr_adj_ok(nbr)) { 549 if (nbr->state == NBR_STA_2_WAY) 550 return (nbr_act_eval(nbr)); 551 } else { 552 nbr->state = NBR_STA_2_WAY; 553 return (nbr_act_clear_lists(nbr)); 554 } 555 556 return (0); 557 } 558 559 int 560 nbr_act_restart_dd(struct nbr *nbr) 561 { 562 nbr_act_clear_lists(nbr); 563 564 if (!nbr_adj_ok(nbr)) { 565 nbr->state = NBR_STA_2_WAY; 566 return (0); 567 } 568 569 nbr->state = NBR_STA_XSTRT; 570 nbr->master = 1; 571 nbr->dd_seq_num += arc4random() & 0xffff; 572 nbr->dd_pending = 0; 573 574 /* initial db negotiation */ 575 start_db_tx_timer(nbr); 576 577 nbr_start_adj_timer(nbr); 578 579 return (0); 580 } 581 582 int 583 nbr_act_delete(struct nbr *nbr) 584 { 585 struct timeval tv; 586 587 if (nbr == nbr->iface->self) 588 return (0); 589 590 /* stop timers */ 591 nbr_stop_itimer(nbr); 592 593 /* clear dr and bdr */ 594 nbr->dr.s_addr = 0; 595 nbr->bdr.s_addr = 0; 596 nbr->crypt_seq_num = 0; 597 598 /* schedule kill timer */ 599 timerclear(&tv); 600 tv.tv_sec = DEFAULT_NBR_TMOUT; 601 602 if (evtimer_add(&nbr->inactivity_timer, &tv)) { 603 log_warnx("nbr_act_delete: error scheduling neighbor ID %s " 604 "for removal", inet_ntoa(nbr->id)); 605 } 606 607 return (nbr_act_clear_lists(nbr)); 608 } 609 610 int 611 nbr_act_clear_lists(struct nbr *nbr) 612 { 613 /* stop timers */ 614 stop_db_tx_timer(nbr); 615 stop_ls_req_tx_timer(nbr); 616 617 /* clear lists */ 618 ls_retrans_list_clr(nbr); 619 db_sum_list_clr(nbr); 620 ls_req_list_clr(nbr); 621 622 return (0); 623 } 624 625 int 626 nbr_act_hello_check(struct nbr *nbr) 627 { 628 log_debug("nbr_act_hello_check: neighbor ID %s", inet_ntoa(nbr->id)); 629 630 return (-1); 631 } 632 633 struct ctl_nbr * 634 nbr_to_ctl(struct nbr *nbr) 635 { 636 static struct ctl_nbr nctl; 637 struct timeval tv, now, res; 638 struct lsa_entry *le; 639 640 memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name)); 641 memcpy(&nctl.id, &nbr->id, sizeof(nctl.id)); 642 memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr)); 643 memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr)); 644 memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr)); 645 memcpy(&nctl.area, &nbr->iface->area->id, sizeof(nctl.area)); 646 647 /* this list is 99% of the time empty so that's OK for now */ 648 nctl.db_sum_lst_cnt = 0; 649 TAILQ_FOREACH(le, &nbr->db_sum_list, entry) 650 nctl.db_sum_lst_cnt++; 651 652 nctl.ls_req_lst_cnt = nbr->ls_req_cnt; 653 nctl.ls_retrans_lst_cnt = nbr->ls_ret_cnt; 654 655 nctl.nbr_state = nbr->state; 656 657 /* 658 * We need to trick a bit to show the remote iface state. 659 * The idea is to print DR, BDR or DROther dependent on 660 * the type of the neighbor. 661 */ 662 if (nbr->iface->dr == nbr) 663 nctl.iface_state = IF_STA_DR; 664 else if (nbr->iface->bdr == nbr) 665 nctl.iface_state = IF_STA_BACKUP; 666 else if (nbr->iface->state & IF_STA_MULTI) 667 nctl.iface_state = IF_STA_DROTHER; 668 else 669 nctl.iface_state = nbr->iface->state; 670 671 nctl.state_chng_cnt = nbr->stats.sta_chng; 672 673 nctl.priority = nbr->priority; 674 nctl.options = nbr->options; 675 676 gettimeofday(&now, NULL); 677 if (evtimer_pending(&nbr->inactivity_timer, &tv)) { 678 timersub(&tv, &now, &res); 679 if (nbr->state & NBR_STA_DOWN) 680 nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec; 681 else 682 nctl.dead_timer = res.tv_sec; 683 } else 684 nctl.dead_timer = 0; 685 686 if (nbr->state == NBR_STA_FULL) { 687 nctl.uptime = now.tv_sec - nbr->uptime; 688 } else 689 nctl.uptime = 0; 690 691 return (&nctl); 692 } 693 694 struct lsa_hdr * 695 lsa_hdr_new(void) 696 { 697 struct lsa_hdr *lsa_hdr = NULL; 698 699 if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL) 700 fatal("lsa_hdr_new"); 701 702 return (lsa_hdr); 703 } 704