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