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