1 /* $OpenBSD: neighbor.c,v 1.3 2009/08/01 12:47:02 michele Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/time.h> 24 #include <sys/socket.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <net/if.h> 28 29 #include <ctype.h> 30 #include <err.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <event.h> 35 #include <unistd.h> 36 37 #include "ldpd.h" 38 #include "ldp.h" 39 #include "ldpe.h" 40 #include "log.h" 41 #include "lde.h" 42 43 int nbr_establish_connection(struct nbr *); 44 void nbr_send_labelmappings(struct nbr *); 45 46 LIST_HEAD(nbr_head, nbr); 47 48 struct nbr_table { 49 struct nbr_head *hashtbl; 50 u_int32_t hashmask; 51 } nbrtable; 52 53 #define NBR_HASH(x) \ 54 &nbrtable.hashtbl[(x) & nbrtable.hashmask] 55 56 u_int32_t peercnt = NBR_CNTSTART; 57 58 extern struct ldpd_conf *leconf; 59 60 struct { 61 int state; 62 enum nbr_event event; 63 enum nbr_action action; 64 int new_state; 65 } nbr_fsm_tbl[] = { 66 /* current state event that happened action to take resulting state */ 67 /* Discovery States */ 68 {NBR_STA_DOWN, NBR_EVT_HELLO_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_PRESENT}, 69 {NBR_STA_UP, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, 0}, 70 /* Passive Role */ 71 {NBR_STA_PRESENT, NBR_EVT_SESSION_UP, NBR_ACT_SESSION_EST, NBR_STA_INITIAL}, 72 {NBR_STA_INITIAL, NBR_EVT_INIT_RCVD, NBR_ACT_INIT_SEND, NBR_STA_OPENREC}, 73 {NBR_STA_OPENREC, NBR_EVT_KEEPALIVE_RCVD, NBR_ACT_STRT_KTIMER, NBR_STA_OPER}, 74 /* Active Role */ 75 {NBR_STA_PRESENT, NBR_EVT_INIT_SENT, NBR_ACT_NOTHING, NBR_STA_OPENSENT}, 76 {NBR_STA_OPENSENT, NBR_EVT_INIT_RCVD, NBR_ACT_KEEPALIVE_SEND, NBR_STA_OPER}, 77 /* Session Maintenance */ 78 {NBR_STA_OPER, NBR_EVT_PDU_RCVD, NBR_ACT_RST_KTIMEOUT, 0}, 79 /* Session Close */ 80 {NBR_STA_SESSION, NBR_EVT_CLOSE_SESSION, NBR_ACT_CLOSE_SESSION, NBR_STA_PRESENT}, 81 {NBR_STA_UP, NBR_EVT_DOWN, NBR_ACT_CLOSE_SESSION, }, 82 {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0}, 83 }; 84 85 const char * const nbr_event_names[] = { 86 "NOTHING", 87 "HELLO RECEIVED", 88 "SESSION UP", 89 "SESSION CLOSE", 90 "INIT RECEIVED", 91 "KEEPALIVE RECEIVED", 92 "PDU RECEIVED", 93 "INIT SENT", 94 "DOWN" 95 }; 96 97 const char * const nbr_action_names[] = { 98 "NOTHING", 99 "START INACTIVITY TIMER", 100 "RESET INACTIVITY TIMER", 101 "RESET KEEPALIVE TIMEOUT", 102 "START KEEPALIVE TIMER", 103 "RESET KEEPALIVE TIMER", 104 "START NEIGHBOR SESSION", 105 "SEND INIT", 106 "SEND KEEPALIVE", 107 "CLOSE SESSION" 108 }; 109 110 int 111 nbr_fsm(struct nbr *nbr, enum nbr_event event) 112 { 113 struct timeval now; 114 int old_state; 115 int new_state = 0; 116 int i, ret = 0; 117 118 if (nbr == nbr->iface->self) 119 return (0); 120 121 old_state = nbr->state; 122 for (i = 0; nbr_fsm_tbl[i].state != -1; i++) 123 if ((nbr_fsm_tbl[i].state & old_state) && 124 (nbr_fsm_tbl[i].event == event)) { 125 new_state = nbr_fsm_tbl[i].new_state; 126 break; 127 } 128 129 if (nbr_fsm_tbl[i].state == -1) { 130 /* event outside of the defined fsm, ignore it. */ 131 log_warnx("nbr_fsm: neighbor ID %s, " 132 "event %s not expected in state %s", 133 inet_ntoa(nbr->id), nbr_event_names[event], 134 nbr_state_name(old_state)); 135 return (0); 136 } 137 138 switch (nbr_fsm_tbl[i].action) { 139 case NBR_ACT_RST_ITIMER: 140 ret = nbr_act_reset_itimer(nbr); 141 break; 142 case NBR_ACT_STRT_ITIMER: 143 ret = nbr_act_start_itimer(nbr); 144 break; 145 case NBR_ACT_RST_KTIMEOUT: 146 ret = nbr_act_reset_ktimeout(nbr); 147 break; 148 case NBR_ACT_RST_KTIMER: 149 ret = nbr_act_reset_ktimer(nbr); 150 break; 151 case NBR_ACT_STRT_KTIMER: 152 /* XXX */ 153 ret = nbr_act_start_ktimer(nbr); 154 nbr_act_start_ktimeout(nbr); 155 send_address(nbr, NULL); 156 nbr_send_labelmappings(nbr); 157 break; 158 case NBR_ACT_SESSION_EST: 159 ret = nbr_act_session_establish(nbr, 0); 160 break; 161 case NBR_ACT_INIT_SEND: 162 /* XXX */ 163 send_keepalive(nbr); 164 ret = send_init(nbr); 165 break; 166 case NBR_ACT_KEEPALIVE_SEND: 167 /* XXX */ 168 ret = nbr_act_start_ktimer(nbr); 169 nbr_act_start_ktimeout(nbr); 170 send_keepalive(nbr); 171 send_address(nbr, NULL); 172 nbr_send_labelmappings(nbr); 173 break; 174 case NBR_ACT_CLOSE_SESSION: 175 session_close(nbr); 176 ret = nbr_act_start_idtimer(nbr); 177 break; 178 case NBR_ACT_NOTHING: 179 /* do nothing */ 180 break; 181 } 182 183 if (ret) { 184 log_warnx("nbr_fsm: error changing state for neighbor ID %s, " 185 "event %s, state %s", inet_ntoa(nbr->id), 186 nbr_event_names[event], nbr_state_name(old_state)); 187 return (-1); 188 } 189 190 if (new_state != 0) 191 nbr->state = new_state; 192 193 if (old_state != nbr->state) { 194 log_debug("nbr_fsm: event %s resulted in action %s and " 195 "changing state for neighbor ID %s from %s to %s", 196 nbr_event_names[event], 197 nbr_action_names[nbr_fsm_tbl[i].action], 198 inet_ntoa(nbr->id), nbr_state_name(old_state), 199 nbr_state_name(nbr->state)); 200 201 if (nbr->state == NBR_STA_OPER) { 202 gettimeofday(&now, NULL); 203 nbr->uptime = now.tv_sec; 204 } 205 } 206 207 return (ret); 208 } 209 210 void 211 nbr_init(u_int32_t hashsize) 212 { 213 struct nbr_head *head; 214 struct nbr *nbr; 215 u_int32_t hs, i; 216 217 for (hs = 1; hs < hashsize; hs <<= 1) 218 ; 219 nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head)); 220 if (nbrtable.hashtbl == NULL) 221 fatal("nbr_init"); 222 223 for (i = 0; i < hs; i++) 224 LIST_INIT(&nbrtable.hashtbl[i]); 225 226 nbrtable.hashmask = hs - 1; 227 228 /* allocate a dummy neighbor used for self originated AS ext routes */ 229 if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 230 fatal("nbr_init"); 231 232 nbr->id.s_addr = ldpe_router_id(); 233 nbr->state = NBR_STA_DOWN; 234 nbr->peerid = NBR_IDSELF; 235 head = NBR_HASH(nbr->peerid); 236 LIST_INSERT_HEAD(head, nbr, hash); 237 238 TAILQ_INIT(&nbr->mapping_list); 239 TAILQ_INIT(&nbr->withdraw_list); 240 TAILQ_INIT(&nbr->request_list); 241 TAILQ_INIT(&nbr->release_list); 242 TAILQ_INIT(&nbr->abortreq_list); 243 } 244 245 struct nbr * 246 nbr_new(u_int32_t nbr_id, u_int16_t lspace, struct iface *iface, int self) 247 { 248 struct nbr_head *head; 249 struct nbr *nbr; 250 struct lde_nbr rn; 251 252 if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 253 fatal("nbr_new"); 254 255 nbr->state = NBR_STA_DOWN; 256 nbr->id.s_addr = nbr_id; 257 nbr->lspace = lspace; 258 259 /* get next unused peerid */ 260 while (nbr_find_peerid(++peercnt)) 261 ; 262 nbr->peerid = peercnt; 263 head = NBR_HASH(nbr->peerid); 264 LIST_INSERT_HEAD(head, nbr, hash); 265 266 /* add to peer list */ 267 nbr->iface = iface; 268 LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry); 269 270 if (self) { 271 nbr->addr.s_addr = iface->addr.s_addr; 272 nbr->priority = iface->priority; 273 } 274 275 /* set event structures */ 276 evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr); 277 evtimer_set(&nbr->keepalive_timeout, nbr_ktimeout, nbr); 278 evtimer_set(&nbr->keepalive_timer, nbr_ktimer, nbr); 279 evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr); 280 281 bzero(&rn, sizeof(rn)); 282 rn.id.s_addr = nbr->id.s_addr; 283 rn.lspace = nbr->lspace; 284 rn.ifindex = nbr->iface->ifindex; 285 rn.self = self; 286 ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn, 287 sizeof(rn)); 288 289 return (nbr); 290 } 291 292 void 293 nbr_del(struct nbr *nbr) 294 { 295 ldpe_imsg_compose_lde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0); 296 297 if (evtimer_pending(&nbr->inactivity_timer, NULL)) 298 evtimer_del(&nbr->inactivity_timer); 299 if (evtimer_pending(&nbr->keepalive_timer, NULL)) 300 evtimer_del(&nbr->keepalive_timer); 301 if (evtimer_pending(&nbr->keepalive_timeout, NULL)) 302 evtimer_del(&nbr->keepalive_timeout); 303 if (evtimer_pending(&nbr->initdelay_timer, NULL)) 304 evtimer_del(&nbr->initdelay_timer); 305 306 nbr_mapping_list_clr(nbr, &nbr->mapping_list); 307 308 LIST_REMOVE(nbr, entry); 309 LIST_REMOVE(nbr, hash); 310 311 free(nbr); 312 } 313 314 struct nbr * 315 nbr_find_peerid(u_int32_t peerid) 316 { 317 struct nbr_head *head; 318 struct nbr *nbr; 319 320 head = NBR_HASH(peerid); 321 322 LIST_FOREACH(nbr, head, hash) { 323 if (nbr->peerid == peerid) 324 return (nbr); 325 } 326 327 return (NULL); 328 } 329 330 struct nbr * 331 nbr_find_ip(struct iface *iface, u_int32_t rtr_id) 332 { 333 struct nbr *nbr = NULL; 334 335 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 336 if (nbr->addr.s_addr == rtr_id) 337 return (nbr); 338 } 339 340 return (NULL); 341 } 342 343 struct nbr * 344 nbr_find_ldpid(struct iface *iface, u_int32_t rtr_id, u_int16_t lspace) 345 { 346 struct nbr *nbr = NULL; 347 348 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 349 if (nbr->id.s_addr == rtr_id && nbr->lspace == lspace) 350 return (nbr); 351 } 352 353 return (NULL); 354 } 355 356 /* timers */ 357 358 /* Inactivity timer: timeout based on hellos */ 359 /* ARGSUSED */ 360 void 361 nbr_itimer(int fd, short event, void *arg) 362 { 363 struct nbr *nbr = arg; 364 365 log_debug("nbr_itimer: neighbor ID %s peerid %lu", inet_ntoa(nbr->id), 366 nbr->peerid); 367 368 nbr_del(nbr); 369 } 370 371 void 372 nbr_start_itimer(struct nbr *nbr) 373 { 374 struct timeval tv; 375 376 timerclear(&tv); 377 tv.tv_sec = nbr->holdtime; 378 379 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1) 380 fatal("nbr_start_itimer"); 381 } 382 383 void 384 nbr_stop_itimer(struct nbr *nbr) 385 { 386 if (evtimer_del(&nbr->inactivity_timer) == -1) 387 fatal("nbr_stop_itimer"); 388 } 389 390 void 391 nbr_reset_itimer(struct nbr *nbr) 392 { 393 struct timeval tv; 394 395 timerclear(&tv); 396 tv.tv_sec = nbr->holdtime; 397 398 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1) 399 fatal("nbr_reset_itimer"); 400 } 401 402 /* Keepalive timer: timer to send keepalive message to neighbors */ 403 404 void 405 nbr_ktimer(int fd, short event, void *arg) 406 { 407 struct nbr *nbr = arg; 408 struct timeval tv; 409 410 log_debug("nbr_ktimer: neighbor ID %s peerid %lu", inet_ntoa(nbr->id), 411 nbr->peerid); 412 413 send_keepalive(nbr); 414 415 timerclear(&tv); 416 tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD); 417 if (evtimer_add(&nbr->keepalive_timer, &tv) == -1) 418 fatal("nbr_ktimer"); 419 } 420 421 void 422 nbr_start_ktimer(struct nbr *nbr) 423 { 424 struct timeval tv; 425 426 timerclear(&tv); 427 428 /* XXX: just to be sure it will send three keepalives per period */ 429 tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD); 430 431 if (evtimer_add(&nbr->keepalive_timer, &tv) == -1) 432 fatal("nbr_start_ktimer"); 433 } 434 435 void 436 nbr_stop_ktimer(struct nbr *nbr) 437 { 438 if (evtimer_del(&nbr->keepalive_timer) == -1) 439 fatal("nbr_stop_ktimer"); 440 } 441 442 void 443 nbr_reset_ktimer(struct nbr *nbr) 444 { 445 struct timeval tv; 446 447 timerclear(&tv); 448 449 /* XXX: just to be sure it will send three keepalives per period */ 450 tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD); 451 452 if (evtimer_add(&nbr->keepalive_timer, &tv) == -1) 453 fatal("nbr_reset_ktimer"); 454 } 455 456 /* Keepalive timeout: if the nbr hasn't sent keepalive */ 457 458 void 459 nbr_ktimeout(int fd, short event, void *arg) 460 { 461 struct nbr *nbr = arg; 462 463 log_debug("nbr_ktimeout: neighbor ID %s peerid %lu", inet_ntoa(nbr->id), 464 nbr->peerid); 465 466 send_notification_nbr(nbr, S_KEEPALIVE_TMR, 0, 0); 467 close(nbr->fd); 468 } 469 470 void 471 nbr_start_ktimeout(struct nbr *nbr) 472 { 473 struct timeval tv; 474 475 timerclear(&tv); 476 tv.tv_sec = nbr->keepalive; 477 478 if (evtimer_add(&nbr->keepalive_timeout, &tv) == -1) 479 fatal("nbr_start_ktimeout"); 480 } 481 482 void 483 nbr_stop_ktimeout(struct nbr *nbr) 484 { 485 if (evtimer_del(&nbr->keepalive_timeout) == -1) 486 fatal("nbr_stop_ktimeout"); 487 } 488 489 void 490 nbr_reset_ktimeout(struct nbr *nbr) 491 { 492 struct timeval tv; 493 494 timerclear(&tv); 495 tv.tv_sec = nbr->keepalive; 496 497 if (evtimer_add(&nbr->keepalive_timeout, &tv) == -1) 498 fatal("nbr_reset_ktimeout"); 499 } 500 501 /* Init delay timer: timer to retry to iniziatize session */ 502 503 void 504 nbr_idtimer(int fd, short event, void *arg) 505 { 506 struct nbr *nbr = arg; 507 508 log_debug("nbr_idtimer: neighbor ID %s peerid %lu", inet_ntoa(nbr->id), 509 nbr->peerid); 510 511 nbr_act_session_establish(nbr, 1); 512 } 513 514 void 515 nbr_start_idtimer(struct nbr *nbr) 516 { 517 struct timeval tv; 518 519 timerclear(&tv); 520 tv.tv_sec = INIT_DELAY_TMR; 521 522 if (evtimer_add(&nbr->initdelay_timer, &tv) == -1) 523 fatal("nbr_start_idtimer"); 524 } 525 526 void 527 nbr_stop_idtimer(struct nbr *nbr) 528 { 529 if (evtimer_del(&nbr->initdelay_timer) == -1) 530 fatal("nbr_stop_idtimer"); 531 } 532 533 int 534 nbr_pending_idtimer(struct nbr *nbr) 535 { 536 if (evtimer_pending(&nbr->initdelay_timer, NULL)) 537 return (1); 538 539 return (0); 540 } 541 542 543 void 544 nbr_reset_idtimer(struct nbr *nbr) 545 { 546 struct timeval tv; 547 548 timerclear(&tv); 549 tv.tv_sec = INIT_DELAY_TMR; 550 551 if (evtimer_add(&nbr->initdelay_timer, &tv) == -1) 552 fatal("nbr_reset_idtimer"); 553 } 554 /* actions */ 555 int 556 nbr_act_reset_itimer(struct nbr *nbr) 557 { 558 nbr_reset_itimer(nbr); 559 560 return (0); 561 } 562 563 int 564 nbr_act_start_itimer(struct nbr *nbr) 565 { 566 nbr_start_itimer(nbr); 567 568 return (0); 569 } 570 571 int 572 nbr_act_reset_ktimer(struct nbr *nbr) 573 { 574 nbr_reset_ktimer(nbr); 575 576 return (0); 577 } 578 579 int 580 nbr_act_start_ktimer(struct nbr *nbr) 581 { 582 nbr_start_ktimer(nbr); 583 584 return (0); 585 } 586 587 int 588 nbr_act_reset_ktimeout(struct nbr *nbr) 589 { 590 nbr_reset_ktimeout(nbr); 591 592 return (0); 593 } 594 595 int 596 nbr_act_start_ktimeout(struct nbr *nbr) 597 { 598 nbr_start_ktimeout(nbr); 599 600 return (0); 601 } 602 603 int 604 nbr_act_reset_idtimer(struct nbr *nbr) 605 { 606 nbr_reset_idtimer(nbr); 607 608 return (0); 609 } 610 611 int 612 nbr_act_start_idtimer(struct nbr *nbr) 613 { 614 if (nbr->addr.s_addr < nbr->iface->addr.s_addr) 615 nbr_start_idtimer(nbr); 616 617 return (0); 618 } 619 620 int 621 nbr_establish_connection(struct nbr *nbr) 622 { 623 struct sockaddr_in in; 624 int st; 625 626 in.sin_family = AF_INET; 627 in.sin_port = htons(LDP_PORT); 628 in.sin_addr.s_addr = nbr->addr.s_addr; 629 630 nbr->fd = socket(AF_INET, SOCK_STREAM, 0); 631 if (nbr->fd < 0) { 632 log_debug("nbr_establish_connection: error while " 633 "creating socket"); 634 return (-1); 635 } 636 637 st = connect(nbr->fd, (struct sockaddr *)&in, sizeof(in)); 638 if (st < 0 ) { 639 log_debug("nbr_establish_connection: error while " 640 "connecting to %s", inet_ntoa(nbr->addr)); 641 nbr_act_start_idtimer(nbr); 642 return (-1); 643 } 644 645 return (0); 646 } 647 648 int 649 nbr_close_connection(struct nbr *nbr) 650 { 651 bufferevent_disable(nbr->bev, EV_READ|EV_WRITE); 652 bufferevent_free(nbr->bev); 653 close(nbr->fd); 654 655 return (0); 656 } 657 658 int 659 nbr_act_session_establish(struct nbr *nbr, int active) 660 { 661 evbuffercb readfn = session_read; 662 everrorcb errorfn = session_error; 663 664 if (active) { 665 if (nbr_establish_connection(nbr) < 0) 666 return (-1); 667 } 668 669 nbr->bev = bufferevent_new(nbr->fd, readfn, NULL, errorfn, nbr); 670 bufferevent_settimeout(nbr->bev, 0, 0); 671 bufferevent_enable(nbr->bev, EV_READ|EV_WRITE); 672 673 if (active) { 674 send_init(nbr); 675 nbr_fsm(nbr, NBR_EVT_INIT_SENT); 676 } 677 678 679 return (0); 680 } 681 682 void 683 nbr_send_labelmappings(struct nbr *nbr) 684 { 685 if (leconf->mode & MODE_ADV_UNSOLICITED) { 686 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING_FULL, nbr->peerid, 0, 687 0, 0); 688 } 689 } 690 691 void 692 nbr_mapping_add(struct nbr *nbr, struct mapping_head *mh, struct map *map) 693 { 694 struct mapping_entry *me; 695 696 me = calloc(1, sizeof(*me)); 697 if (me == NULL) 698 fatal("nbr_mapping_add"); 699 700 me->prefix = map->prefix; 701 me->prefixlen = map->prefixlen; 702 me->label = map->label; 703 704 TAILQ_INSERT_HEAD(mh, me, entry); 705 } 706 707 struct mapping_entry * 708 nbr_mapping_find(struct nbr *nbr, struct mapping_head *mh, struct map *map) 709 { 710 struct mapping_entry *me = NULL; 711 712 TAILQ_FOREACH(me, mh, entry) { 713 if (me->prefix == map->prefix && 714 me->prefixlen == map->prefixlen) 715 return (me); 716 } 717 718 return (NULL); 719 } 720 721 void 722 nbr_mapping_del(struct nbr *nbr, struct mapping_head *mh, struct map *map) 723 { 724 struct mapping_entry *me; 725 726 me = nbr_mapping_find(nbr, mh, map); 727 if (me == NULL) 728 return; 729 730 TAILQ_REMOVE(mh, me, entry); 731 free(me); 732 } 733 734 void 735 nbr_mapping_list_clr(struct nbr *nbr, struct mapping_head *mh) 736 { 737 struct mapping_entry *me; 738 739 while ((me = TAILQ_FIRST(mh)) != NULL) { 740 TAILQ_REMOVE(mh, me, entry); 741 free(me); 742 } 743 } 744 745 struct ctl_nbr * 746 nbr_to_ctl(struct nbr *nbr) 747 { 748 static struct ctl_nbr nctl; 749 struct timeval tv, now, res; 750 751 memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name)); 752 memcpy(&nctl.id, &nbr->id, sizeof(nctl.id)); 753 memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr)); 754 755 nctl.nbr_state = nbr->state; 756 nctl.iface_state = nbr->iface->state; 757 758 gettimeofday(&now, NULL); 759 if (evtimer_pending(&nbr->inactivity_timer, &tv)) { 760 timersub(&tv, &now, &res); 761 if (nbr->state & NBR_STA_DOWN) 762 nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec; 763 else 764 nctl.dead_timer = res.tv_sec; 765 } else 766 nctl.dead_timer = 0; 767 768 if (nbr->state == NBR_STA_OPER) { 769 nctl.uptime = now.tv_sec - nbr->uptime; 770 } else 771 nctl.uptime = 0; 772 773 return (&nctl); 774 } 775