1*f1b790a5Sclaudio /* $OpenBSD: ospfe.c,v 1.120 2024/11/21 13:38:14 claudio Exp $ */ 2204df0f8Sclaudio 3204df0f8Sclaudio /* 4204df0f8Sclaudio * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5367f601bSnorby * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6204df0f8Sclaudio * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7204df0f8Sclaudio * 8204df0f8Sclaudio * Permission to use, copy, modify, and distribute this software for any 9204df0f8Sclaudio * purpose with or without fee is hereby granted, provided that the above 10204df0f8Sclaudio * copyright notice and this permission notice appear in all copies. 11204df0f8Sclaudio * 12204df0f8Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13204df0f8Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14204df0f8Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15204df0f8Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16204df0f8Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17204df0f8Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18204df0f8Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19204df0f8Sclaudio */ 20204df0f8Sclaudio 21204df0f8Sclaudio #include <sys/types.h> 22204df0f8Sclaudio #include <sys/socket.h> 23204df0f8Sclaudio #include <sys/queue.h> 24204df0f8Sclaudio #include <netinet/in.h> 25204df0f8Sclaudio #include <arpa/inet.h> 26d7a91d7eSclaudio #include <net/if_types.h> 27204df0f8Sclaudio #include <stdlib.h> 28204df0f8Sclaudio #include <signal.h> 29204df0f8Sclaudio #include <string.h> 30204df0f8Sclaudio #include <fcntl.h> 31204df0f8Sclaudio #include <pwd.h> 32204df0f8Sclaudio #include <unistd.h> 33204df0f8Sclaudio #include <event.h> 34204df0f8Sclaudio #include <err.h> 35204df0f8Sclaudio #include <errno.h> 36204df0f8Sclaudio #include <stdio.h> 37204df0f8Sclaudio 38204df0f8Sclaudio #include "ospf.h" 39204df0f8Sclaudio #include "ospfd.h" 40204df0f8Sclaudio #include "ospfe.h" 41a59bf5b7Snorby #include "rde.h" 42204df0f8Sclaudio #include "control.h" 43204df0f8Sclaudio #include "log.h" 44204df0f8Sclaudio 45204df0f8Sclaudio void ospfe_sig_handler(int, short, void *); 46a27c0559Srenato __dead void ospfe_shutdown(void); 47317d560cSclaudio void orig_rtr_lsa_all(struct area *); 48a59bf5b7Snorby struct iface *find_vlink(struct abr_rtr *); 49204df0f8Sclaudio 50d8606ed9Sclaudio struct ospfd_conf *oeconf = NULL, *noeconf; 51d8606ed9Sclaudio static struct imsgev *iev_main; 52d8606ed9Sclaudio static struct imsgev *iev_rde; 531891964aSclaudio int oe_nofib; 54204df0f8Sclaudio 55204df0f8Sclaudio void 56204df0f8Sclaudio ospfe_sig_handler(int sig, short event, void *bula) 57204df0f8Sclaudio { 58204df0f8Sclaudio switch (sig) { 59204df0f8Sclaudio case SIGINT: 60204df0f8Sclaudio case SIGTERM: 61204df0f8Sclaudio ospfe_shutdown(); 62204df0f8Sclaudio /* NOTREACHED */ 63204df0f8Sclaudio default: 64204df0f8Sclaudio fatalx("unexpected signal"); 65204df0f8Sclaudio } 66204df0f8Sclaudio } 67204df0f8Sclaudio 68204df0f8Sclaudio /* ospf engine */ 69204df0f8Sclaudio pid_t 70204df0f8Sclaudio ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2], 71204df0f8Sclaudio int pipe_parent2rde[2]) 72204df0f8Sclaudio { 738b1d5e52Sclaudio struct area *area; 748b1d5e52Sclaudio struct iface *iface; 75baf6ff01Sclaudio struct redistribute *r; 76204df0f8Sclaudio struct passwd *pw; 77204df0f8Sclaudio struct event ev_sigint, ev_sigterm; 78204df0f8Sclaudio pid_t pid; 79204df0f8Sclaudio 80204df0f8Sclaudio switch (pid = fork()) { 81204df0f8Sclaudio case -1: 82204df0f8Sclaudio fatal("cannot fork"); 83204df0f8Sclaudio case 0: 84204df0f8Sclaudio break; 85204df0f8Sclaudio default: 86204df0f8Sclaudio return (pid); 87204df0f8Sclaudio } 88204df0f8Sclaudio 89358269bbSclaudio /* cleanup a bit */ 90358269bbSclaudio kif_clear(); 91358269bbSclaudio 9229627493Sclaudio /* create the raw ip socket */ 9358ef7452Sclaudio if ((xconf->ospf_socket = socket(AF_INET, 9458ef7452Sclaudio SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 9529627493Sclaudio IPPROTO_OSPF)) == -1) 9629627493Sclaudio fatal("error creating raw socket"); 9729627493Sclaudio 9829627493Sclaudio /* set some defaults */ 9929627493Sclaudio if (if_set_mcast_loop(xconf->ospf_socket) == -1) 10029627493Sclaudio fatal("if_set_mcast_loop"); 10166dd3991Sclaudio if (if_set_ip_hdrincl(xconf->ospf_socket) == -1) 10266dd3991Sclaudio fatal("if_set_ip_hdrincl"); 103e29a452cSclaudio if (if_set_recvif(xconf->ospf_socket, 1) == -1) 104e29a452cSclaudio fatal("if_set_recvif"); 105b07e4035Sclaudio if_set_sockbuf(xconf->ospf_socket); 106cfb36fa8Snorby 107204df0f8Sclaudio oeconf = xconf; 1081891964aSclaudio if (oeconf->flags & OSPFD_FLAG_NO_FIB_UPDATE) 1091891964aSclaudio oe_nofib = 1; 110204df0f8Sclaudio 111204df0f8Sclaudio if ((pw = getpwnam(OSPFD_USER)) == NULL) 112204df0f8Sclaudio fatal("getpwnam"); 113204df0f8Sclaudio 114204df0f8Sclaudio if (chroot(pw->pw_dir) == -1) 115204df0f8Sclaudio fatal("chroot"); 116204df0f8Sclaudio if (chdir("/") == -1) 117204df0f8Sclaudio fatal("chdir(\"/\")"); 118204df0f8Sclaudio 119204df0f8Sclaudio setproctitle("ospf engine"); 120f2e37bc3Sbenno /* 121f2e37bc3Sbenno * XXX needed with fork+exec 122f2e37bc3Sbenno * log_init(debug, LOG_DAEMON); 123f2e37bc3Sbenno * log_setverbose(verbose); 124f2e37bc3Sbenno */ 125f2e37bc3Sbenno 126204df0f8Sclaudio ospfd_process = PROC_OSPF_ENGINE; 127f2e37bc3Sbenno log_procinit(log_procnames[ospfd_process]); 128204df0f8Sclaudio 129204df0f8Sclaudio if (setgroups(1, &pw->pw_gid) || 130f8595d30Sdjm setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 131f8595d30Sdjm setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 132204df0f8Sclaudio fatal("can't drop privileges"); 133204df0f8Sclaudio 134617bb465Sremi if (pledge("stdio inet mcast recvfd", NULL) == -1) 135358269bbSclaudio fatal("pledge"); 136358269bbSclaudio 137204df0f8Sclaudio event_init(); 138204df0f8Sclaudio nbr_init(NBR_HASHSIZE); 139204df0f8Sclaudio lsa_cache_init(LSA_HASHSIZE); 140204df0f8Sclaudio 141204df0f8Sclaudio /* setup signal handler */ 142204df0f8Sclaudio signal_set(&ev_sigint, SIGINT, ospfe_sig_handler, NULL); 143204df0f8Sclaudio signal_set(&ev_sigterm, SIGTERM, ospfe_sig_handler, NULL); 144204df0f8Sclaudio signal_add(&ev_sigint, NULL); 145204df0f8Sclaudio signal_add(&ev_sigterm, NULL); 146204df0f8Sclaudio signal(SIGPIPE, SIG_IGN); 1471035f31cSpyr signal(SIGHUP, SIG_IGN); 148204df0f8Sclaudio 149204df0f8Sclaudio /* setup pipes */ 150204df0f8Sclaudio close(pipe_parent2ospfe[0]); 151204df0f8Sclaudio close(pipe_ospfe2rde[1]); 152204df0f8Sclaudio close(pipe_parent2rde[0]); 153204df0f8Sclaudio close(pipe_parent2rde[1]); 154204df0f8Sclaudio 1557b4c0c10Seric if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL || 1567b4c0c10Seric (iev_main = malloc(sizeof(struct imsgev))) == NULL) 157204df0f8Sclaudio fatal(NULL); 158*f1b790a5Sclaudio if (imsgbuf_init(&iev_rde->ibuf, pipe_ospfe2rde[0]) == -1) 159*f1b790a5Sclaudio fatal(NULL); 1607b4c0c10Seric iev_rde->handler = ospfe_dispatch_rde; 161*f1b790a5Sclaudio if (imsgbuf_init(&iev_main->ibuf, pipe_parent2ospfe[1]) == -1) 162*f1b790a5Sclaudio fatal(NULL); 163*f1b790a5Sclaudio imsgbuf_allow_fdpass(&iev_main->ibuf); 1647b4c0c10Seric iev_main->handler = ospfe_dispatch_main; 165204df0f8Sclaudio 166204df0f8Sclaudio /* setup event handler */ 1677b4c0c10Seric iev_rde->events = EV_READ; 1687b4c0c10Seric event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 1697b4c0c10Seric iev_rde->handler, iev_rde); 1707b4c0c10Seric event_add(&iev_rde->ev, NULL); 171204df0f8Sclaudio 1727b4c0c10Seric iev_main->events = EV_READ; 1737b4c0c10Seric event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 1747b4c0c10Seric iev_main->handler, iev_main); 1757b4c0c10Seric event_add(&iev_main->ev, NULL); 176204df0f8Sclaudio 177204df0f8Sclaudio event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST, 178204df0f8Sclaudio recv_packet, oeconf); 179204df0f8Sclaudio event_add(&oeconf->ev, NULL); 180204df0f8Sclaudio 181baf6ff01Sclaudio /* remove unneeded config stuff */ 182ac149fe2Sremi conf_clear_redist_list(&oeconf->redist_list); 1836fa28760Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) { 1846fa28760Sclaudio while ((r = SIMPLEQ_FIRST(&area->redist_list)) != NULL) { 1856fa28760Sclaudio SIMPLEQ_REMOVE_HEAD(&area->redist_list, entry); 1866fa28760Sclaudio free(r); 1876fa28760Sclaudio } 1886fa28760Sclaudio } 189baf6ff01Sclaudio 190204df0f8Sclaudio /* start interfaces */ 191204df0f8Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) { 192fba2d3d0Sclaudio ospfe_demote_area(area, 0); 193204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 1941d887742Sclaudio if_init(xconf, iface); 195204df0f8Sclaudio if (if_fsm(iface, IF_EVT_UP)) { 196204df0f8Sclaudio log_debug("error starting interface %s", 197204df0f8Sclaudio iface->name); 198204df0f8Sclaudio } 199204df0f8Sclaudio } 200204df0f8Sclaudio } 201204df0f8Sclaudio 202204df0f8Sclaudio event_dispatch(); 203204df0f8Sclaudio 204204df0f8Sclaudio ospfe_shutdown(); 205204df0f8Sclaudio /* NOTREACHED */ 206204df0f8Sclaudio return (0); 207204df0f8Sclaudio } 208204df0f8Sclaudio 209a27c0559Srenato __dead void 210204df0f8Sclaudio ospfe_shutdown(void) 211204df0f8Sclaudio { 212204df0f8Sclaudio struct area *area; 213204df0f8Sclaudio struct iface *iface; 214204df0f8Sclaudio 215a27c0559Srenato /* close pipes */ 216dd7efffeSclaudio imsgbuf_write(&iev_rde->ibuf); 2179cbf9e90Sclaudio imsgbuf_clear(&iev_rde->ibuf); 218a27c0559Srenato close(iev_rde->ibuf.fd); 219dd7efffeSclaudio imsgbuf_write(&iev_main->ibuf); 2209cbf9e90Sclaudio imsgbuf_clear(&iev_main->ibuf); 221a27c0559Srenato close(iev_main->ibuf.fd); 222a27c0559Srenato 223204df0f8Sclaudio /* stop all interfaces and remove all areas */ 224a3bb4f51Sclaudio while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) { 225204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 226204df0f8Sclaudio if (if_fsm(iface, IF_EVT_DOWN)) { 227204df0f8Sclaudio log_debug("error stopping interface %s", 228204df0f8Sclaudio iface->name); 229204df0f8Sclaudio } 230204df0f8Sclaudio } 231a3bb4f51Sclaudio LIST_REMOVE(area, entry); 232cb4564e5Sclaudio area_del(area); 23340f0e1ddSnorby } 234204df0f8Sclaudio 23572f25908Sclaudio nbr_del(nbr_find_peerid(NBR_IDSELF)); 236674cacadSclaudio close(oeconf->ospf_socket); 237674cacadSclaudio 238204df0f8Sclaudio /* clean up */ 2397b4c0c10Seric free(iev_rde); 2407b4c0c10Seric free(iev_main); 241a3bb4f51Sclaudio free(oeconf); 242204df0f8Sclaudio 243204df0f8Sclaudio log_info("ospf engine exiting"); 244204df0f8Sclaudio _exit(0); 245204df0f8Sclaudio } 246204df0f8Sclaudio 247204df0f8Sclaudio /* imesg */ 248204df0f8Sclaudio int 249204df0f8Sclaudio ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 250204df0f8Sclaudio { 2517b4c0c10Seric return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 252204df0f8Sclaudio } 253204df0f8Sclaudio 254204df0f8Sclaudio int 255204df0f8Sclaudio ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, 256204df0f8Sclaudio void *data, u_int16_t datalen) 257204df0f8Sclaudio { 2587154916cSclaudio return (imsg_compose_event(iev_rde, type, peerid, pid, -1, 2597154916cSclaudio data, datalen)); 260204df0f8Sclaudio } 261204df0f8Sclaudio 262204df0f8Sclaudio void 263204df0f8Sclaudio ospfe_dispatch_main(int fd, short event, void *bula) 264204df0f8Sclaudio { 265f28af201Sclaudio static struct area *narea; 266f28af201Sclaudio static struct iface *niface; 2672dc8313fSremi struct ifaddrchange *ifc; 268204df0f8Sclaudio struct imsg imsg; 2697b4c0c10Seric struct imsgev *iev = bula; 2707154916cSclaudio struct imsgbuf *ibuf = &iev->ibuf; 271204df0f8Sclaudio struct area *area = NULL; 272204df0f8Sclaudio struct iface *iface = NULL; 273204df0f8Sclaudio struct kif *kif; 274f28af201Sclaudio struct auth_md md; 275410c7411Sclaudio int n, link_ok, stub_changed, shut = 0; 276204df0f8Sclaudio 277b202c6d3Sclaudio if (event & EV_READ) { 278668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 279dd7efffeSclaudio fatal("imsgbuf_read error"); 280204df0f8Sclaudio if (n == 0) /* connection closed */ 281410c7411Sclaudio shut = 1; 282b202c6d3Sclaudio } 283b202c6d3Sclaudio if (event & EV_WRITE) { 284dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 285c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 2861203692fSkrw shut = 1; 287c1aa9554Sclaudio else 288dd7efffeSclaudio fatal("imsgbuf_write"); 289c1aa9554Sclaudio } 290204df0f8Sclaudio } 291204df0f8Sclaudio 292204df0f8Sclaudio for (;;) { 293204df0f8Sclaudio if ((n = imsg_get(ibuf, &imsg)) == -1) 2942f207408Sclaudio fatal("ospfe_dispatch_main: imsg_get error"); 295204df0f8Sclaudio if (n == 0) 296204df0f8Sclaudio break; 297204df0f8Sclaudio 298204df0f8Sclaudio switch (imsg.hdr.type) { 299204df0f8Sclaudio case IMSG_IFINFO: 300204df0f8Sclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 301204df0f8Sclaudio sizeof(struct kif)) 302204df0f8Sclaudio fatalx("IFINFO imsg with wrong len"); 303204df0f8Sclaudio kif = imsg.data; 304d7a91d7eSclaudio link_ok = (kif->flags & IFF_UP) && 3059a2e0324Sclaudio LINK_STATE_IS_UP(kif->link_state); 306204df0f8Sclaudio 307204df0f8Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) { 308204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 309a59bf5b7Snorby if (kif->ifindex == iface->ifindex && 310a66fd4eeShenning iface->type != 311a66fd4eeShenning IF_TYPE_VIRTUALLINK) { 312b560dd01Sjca int prev_link_state = 313b560dd01Sjca (iface->flags & IFF_UP) && 314b560dd01Sjca LINK_STATE_IS_UP(iface->linkstate); 315b560dd01Sjca 316e9fa2173Sclaudio iface->flags = kif->flags; 317e9fa2173Sclaudio iface->linkstate = 318e9fa2173Sclaudio kif->link_state; 31940d3ccc4Sjca iface->mtu = kif->mtu; 320d7a91d7eSclaudio 321b560dd01Sjca if (link_ok == prev_link_state) 322b560dd01Sjca break; 323b560dd01Sjca 324d7a91d7eSclaudio if (link_ok) { 325204df0f8Sclaudio if_fsm(iface, 326204df0f8Sclaudio IF_EVT_UP); 327c41cf65fSnorby log_warnx("interface %s" 328c41cf65fSnorby " up", iface->name); 329204df0f8Sclaudio } else { 330204df0f8Sclaudio if_fsm(iface, 331204df0f8Sclaudio IF_EVT_DOWN); 332c41cf65fSnorby log_warnx("interface %s" 333c41cf65fSnorby " down", 334c41cf65fSnorby iface->name); 335204df0f8Sclaudio } 336204df0f8Sclaudio } 337ac149fe2Sremi if (strcmp(kif->ifname, 338ac149fe2Sremi iface->dependon) == 0) { 339ac149fe2Sremi log_warnx("interface %s" 340ac149fe2Sremi " changed state, %s" 341ac149fe2Sremi " depends on it", 342ac149fe2Sremi kif->ifname, 343ac149fe2Sremi iface->name); 344ac149fe2Sremi iface->depend_ok = 345ac149fe2Sremi ifstate_is_up(kif); 346ac149fe2Sremi 347ac149fe2Sremi if ((iface->flags & 348ac149fe2Sremi IFF_UP) && 349ac149fe2Sremi LINK_STATE_IS_UP(iface->linkstate)) 350ac149fe2Sremi orig_rtr_lsa(iface->area); 351ac149fe2Sremi } 352204df0f8Sclaudio } 353204df0f8Sclaudio } 354204df0f8Sclaudio break; 3552dc8313fSremi case IMSG_IFADDRADD: 3562dc8313fSremi if (imsg.hdr.len != IMSG_HEADER_SIZE + 3572dc8313fSremi sizeof(struct ifaddrchange)) 3582dc8313fSremi fatalx("IFADDRADD imsg with wrong len"); 3592dc8313fSremi ifc = imsg.data; 3602dc8313fSremi 3612dc8313fSremi LIST_FOREACH(area, &oeconf->area_list, entry) { 3622dc8313fSremi LIST_FOREACH(iface, &area->iface_list, entry) { 3632dc8313fSremi if (ifc->ifindex == iface->ifindex && 3642dc8313fSremi ifc->addr.s_addr == 3652dc8313fSremi iface->addr.s_addr) { 3662dc8313fSremi iface->mask = ifc->mask; 3672dc8313fSremi iface->dst = ifc->dst; 3682dc8313fSremi /* 3692dc8313fSremi * Previous down event might 3702dc8313fSremi * have failed if the address 3712dc8313fSremi * was not present at that 3722dc8313fSremi * time. 3732dc8313fSremi */ 3742dc8313fSremi if_fsm(iface, IF_EVT_DOWN); 3752dc8313fSremi if_fsm(iface, IF_EVT_UP); 3762dc8313fSremi log_warnx("interface %s:%s " 3772dc8313fSremi "returned", iface->name, 3782dc8313fSremi inet_ntoa(iface->addr)); 3792dc8313fSremi break; 3802dc8313fSremi } 3812dc8313fSremi } 3822dc8313fSremi } 3832dc8313fSremi break; 384a60d5a8aSclaudio case IMSG_IFADDRDEL: 385a60d5a8aSclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 3862dc8313fSremi sizeof(struct ifaddrchange)) 387f1f2f763Sbluhm fatalx("IFADDRDEL imsg with wrong len"); 388a60d5a8aSclaudio ifc = imsg.data; 389a60d5a8aSclaudio 390a60d5a8aSclaudio LIST_FOREACH(area, &oeconf->area_list, entry) { 391a60d5a8aSclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 392a60d5a8aSclaudio if (ifc->ifindex == iface->ifindex && 393a60d5a8aSclaudio ifc->addr.s_addr == 394a60d5a8aSclaudio iface->addr.s_addr) { 395a60d5a8aSclaudio if_fsm(iface, IF_EVT_DOWN); 396a60d5a8aSclaudio log_warnx("interface %s:%s " 397a60d5a8aSclaudio "gone", iface->name, 398a60d5a8aSclaudio inet_ntoa(iface->addr)); 399a60d5a8aSclaudio break; 400a60d5a8aSclaudio } 401a60d5a8aSclaudio } 402a60d5a8aSclaudio } 403a60d5a8aSclaudio break; 404f28af201Sclaudio case IMSG_RECONF_CONF: 405d8606ed9Sclaudio if ((noeconf = malloc(sizeof(struct ospfd_conf))) == 406f28af201Sclaudio NULL) 407f28af201Sclaudio fatal(NULL); 408d8606ed9Sclaudio memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf)); 409f28af201Sclaudio 410d8606ed9Sclaudio LIST_INIT(&noeconf->area_list); 411d8606ed9Sclaudio LIST_INIT(&noeconf->cand_list); 412f28af201Sclaudio break; 413f28af201Sclaudio case IMSG_RECONF_AREA: 414f28af201Sclaudio if ((narea = area_new()) == NULL) 415f28af201Sclaudio fatal(NULL); 416f28af201Sclaudio memcpy(narea, imsg.data, sizeof(struct area)); 417f28af201Sclaudio 418f28af201Sclaudio LIST_INIT(&narea->iface_list); 419f28af201Sclaudio LIST_INIT(&narea->nbr_list); 420f28af201Sclaudio RB_INIT(&narea->lsa_tree); 4216fa28760Sclaudio SIMPLEQ_INIT(&narea->redist_list); 422f28af201Sclaudio 423d8606ed9Sclaudio LIST_INSERT_HEAD(&noeconf->area_list, narea, entry); 424f28af201Sclaudio break; 425f28af201Sclaudio case IMSG_RECONF_IFACE: 426f28af201Sclaudio if ((niface = malloc(sizeof(struct iface))) == NULL) 427f28af201Sclaudio fatal(NULL); 428f28af201Sclaudio memcpy(niface, imsg.data, sizeof(struct iface)); 429f28af201Sclaudio 430f28af201Sclaudio LIST_INIT(&niface->nbr_list); 431f28af201Sclaudio TAILQ_INIT(&niface->ls_ack_list); 432f28af201Sclaudio TAILQ_INIT(&niface->auth_md_list); 433097ed198Sclaudio RB_INIT(&niface->lsa_tree); 434f28af201Sclaudio 435f28af201Sclaudio niface->area = narea; 436f28af201Sclaudio LIST_INSERT_HEAD(&narea->iface_list, niface, entry); 437f28af201Sclaudio break; 438f28af201Sclaudio case IMSG_RECONF_AUTHMD: 439f28af201Sclaudio memcpy(&md, imsg.data, sizeof(struct auth_md)); 440f28af201Sclaudio md_list_add(&niface->auth_md_list, md.keyid, md.key); 441f28af201Sclaudio break; 442f28af201Sclaudio case IMSG_RECONF_END: 4431891964aSclaudio if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) != 444d8606ed9Sclaudio (noeconf->flags & OSPFD_FLAG_STUB_ROUTER)) 4451891964aSclaudio stub_changed = 1; 4461891964aSclaudio else 4471891964aSclaudio stub_changed = 0; 448d8606ed9Sclaudio merge_config(oeconf, noeconf); 449d8606ed9Sclaudio noeconf = NULL; 4501891964aSclaudio if (stub_changed) 4511891964aSclaudio orig_rtr_lsa_all(NULL); 452f28af201Sclaudio break; 453b6b3a59aSclaudio case IMSG_CTL_KROUTE: 454b6b3a59aSclaudio case IMSG_CTL_KROUTE_ADDR: 455b6b3a59aSclaudio case IMSG_CTL_IFINFO: 456204df0f8Sclaudio case IMSG_CTL_END: 457204df0f8Sclaudio control_imsg_relay(&imsg); 458204df0f8Sclaudio break; 459617bb465Sremi case IMSG_CONTROLFD: 46019ca2900Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 461617bb465Sremi fatalx("%s: expected to receive imsg control" 462617bb465Sremi "fd but didn't receive any", __func__); 463617bb465Sremi /* Listen on control socket. */ 46442082862Sclaudio control_listen(fd); 465617bb465Sremi if (pledge("stdio inet mcast", NULL) == -1) 466617bb465Sremi fatal("pledge"); 467617bb465Sremi break; 468204df0f8Sclaudio default: 469204df0f8Sclaudio log_debug("ospfe_dispatch_main: error handling imsg %d", 470204df0f8Sclaudio imsg.hdr.type); 471204df0f8Sclaudio break; 472204df0f8Sclaudio } 473204df0f8Sclaudio imsg_free(&imsg); 474204df0f8Sclaudio } 475410c7411Sclaudio if (!shut) 4767b4c0c10Seric imsg_event_add(iev); 477410c7411Sclaudio else { 478410c7411Sclaudio /* this pipe is dead, so remove the event handler */ 4797b4c0c10Seric event_del(&iev->ev); 480410c7411Sclaudio event_loopexit(NULL); 481410c7411Sclaudio } 482204df0f8Sclaudio } 483204df0f8Sclaudio 484204df0f8Sclaudio void 485204df0f8Sclaudio ospfe_dispatch_rde(int fd, short event, void *bula) 486204df0f8Sclaudio { 487204df0f8Sclaudio struct lsa_hdr lsa_hdr; 4887b4c0c10Seric struct imsgev *iev = bula; 4897154916cSclaudio struct imsgbuf *ibuf = &iev->ibuf; 490204df0f8Sclaudio struct nbr *nbr; 491204df0f8Sclaudio struct lsa_hdr *lhp; 492204df0f8Sclaudio struct lsa_ref *ref; 493204df0f8Sclaudio struct area *area; 494204df0f8Sclaudio struct iface *iface; 495204df0f8Sclaudio struct lsa_entry *le; 496204df0f8Sclaudio struct imsg imsg; 497a59bf5b7Snorby struct abr_rtr ar; 498410c7411Sclaudio int n, noack = 0, shut = 0; 499204df0f8Sclaudio u_int16_t l, age; 500204df0f8Sclaudio 501b202c6d3Sclaudio if (event & EV_READ) { 502668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 503dd7efffeSclaudio fatal("imsgbuf_read error"); 504204df0f8Sclaudio if (n == 0) /* connection closed */ 505410c7411Sclaudio shut = 1; 506b202c6d3Sclaudio } 507b202c6d3Sclaudio if (event & EV_WRITE) { 508dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 509c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 5101203692fSkrw shut = 1; 511c1aa9554Sclaudio else 512dd7efffeSclaudio fatal("imsgbuf_write"); 513c1aa9554Sclaudio } 514204df0f8Sclaudio } 515204df0f8Sclaudio 516204df0f8Sclaudio for (;;) { 517204df0f8Sclaudio if ((n = imsg_get(ibuf, &imsg)) == -1) 5182f207408Sclaudio fatal("ospfe_dispatch_rde: imsg_get error"); 519204df0f8Sclaudio if (n == 0) 520204df0f8Sclaudio break; 521204df0f8Sclaudio 522204df0f8Sclaudio switch (imsg.hdr.type) { 523204df0f8Sclaudio case IMSG_DD: 524204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 525204df0f8Sclaudio if (nbr == NULL) 5268b1d5e52Sclaudio break; 527204df0f8Sclaudio 52898b447a7Sclaudio /* 52998b447a7Sclaudio * Ignore imsg when in the wrong state because a 53098b447a7Sclaudio * NBR_EVT_SEQ_NUM_MIS may have been issued in between. 53198b447a7Sclaudio * Luckily regetting the DB snapshot acts as a barrier 53298b447a7Sclaudio * for both state and process synchronisation. 53398b447a7Sclaudio */ 53498b447a7Sclaudio if ((nbr->state & NBR_STA_FLOOD) == 0) 53598b447a7Sclaudio break; 53698b447a7Sclaudio 537a139c072Sdavid /* put these on my ls_req_list for retrieval */ 538204df0f8Sclaudio lhp = lsa_hdr_new(); 539204df0f8Sclaudio memcpy(lhp, imsg.data, sizeof(*lhp)); 540204df0f8Sclaudio ls_req_list_add(nbr, lhp); 541204df0f8Sclaudio break; 542299d99d9Sclaudio case IMSG_DD_END: 543299d99d9Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 544299d99d9Sclaudio if (nbr == NULL) 5458b1d5e52Sclaudio break; 546299d99d9Sclaudio 54798b447a7Sclaudio /* see above */ 54898b447a7Sclaudio if ((nbr->state & NBR_STA_FLOOD) == 0) 54998b447a7Sclaudio break; 55098b447a7Sclaudio 551299d99d9Sclaudio nbr->dd_pending--; 552299d99d9Sclaudio if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) { 553299d99d9Sclaudio if (ls_req_list_empty(nbr)) 554299d99d9Sclaudio nbr_fsm(nbr, NBR_EVT_LOAD_DONE); 555299d99d9Sclaudio else 556299d99d9Sclaudio start_ls_req_tx_timer(nbr); 557299d99d9Sclaudio } 558299d99d9Sclaudio break; 55998b447a7Sclaudio case IMSG_DD_BADLSA: 56098b447a7Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 56198b447a7Sclaudio if (nbr == NULL) 56298b447a7Sclaudio break; 56398b447a7Sclaudio 56498b447a7Sclaudio if (nbr->iface->self == nbr) 56598b447a7Sclaudio fatalx("ospfe_dispatch_rde: " 56698b447a7Sclaudio "dummy neighbor got BADREQ"); 56798b447a7Sclaudio 56898b447a7Sclaudio nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 56998b447a7Sclaudio break; 570204df0f8Sclaudio case IMSG_DB_SNAPSHOT: 571204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 572204df0f8Sclaudio if (nbr == NULL) 5738b1d5e52Sclaudio break; 574c983ff94Smarkus if (nbr->state != NBR_STA_SNAP) /* discard */ 575c983ff94Smarkus break; 576204df0f8Sclaudio 577204df0f8Sclaudio /* add LSA header to the neighbor db_sum_list */ 578204df0f8Sclaudio lhp = lsa_hdr_new(); 579204df0f8Sclaudio memcpy(lhp, imsg.data, sizeof(*lhp)); 580204df0f8Sclaudio db_sum_list_add(nbr, lhp); 581204df0f8Sclaudio break; 582204df0f8Sclaudio case IMSG_DB_END: 583204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 584204df0f8Sclaudio if (nbr == NULL) 5858b1d5e52Sclaudio break; 586204df0f8Sclaudio 587c983ff94Smarkus nbr->dd_snapshot = 0; 588c983ff94Smarkus if (nbr->state != NBR_STA_SNAP) 589c983ff94Smarkus break; 590c983ff94Smarkus 591204df0f8Sclaudio /* snapshot done, start tx of dd packets */ 592204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_SNAP_DONE); 593204df0f8Sclaudio break; 594204df0f8Sclaudio case IMSG_LS_FLOOD: 595204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 596204df0f8Sclaudio if (nbr == NULL) 5978b1d5e52Sclaudio break; 598204df0f8Sclaudio 599204df0f8Sclaudio l = imsg.hdr.len - IMSG_HEADER_SIZE; 600204df0f8Sclaudio if (l < sizeof(lsa_hdr)) 601204df0f8Sclaudio fatalx("ospfe_dispatch_rde: " 602204df0f8Sclaudio "bad imsg size"); 603204df0f8Sclaudio memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 604204df0f8Sclaudio 605204df0f8Sclaudio ref = lsa_cache_add(imsg.data, l); 606204df0f8Sclaudio 607204df0f8Sclaudio if (lsa_hdr.type == LSA_TYPE_EXTERNAL) { 608204df0f8Sclaudio /* 609204df0f8Sclaudio * flood on all areas but stub areas and 610204df0f8Sclaudio * virtual links 611204df0f8Sclaudio */ 612204df0f8Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) { 613204df0f8Sclaudio if (area->stub) 614204df0f8Sclaudio continue; 615204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, 616204df0f8Sclaudio entry) { 617204df0f8Sclaudio noack += lsa_flood(iface, nbr, 61859eccb25Snorby &lsa_hdr, imsg.data); 619204df0f8Sclaudio } 620204df0f8Sclaudio } 621097ed198Sclaudio } else if (lsa_hdr.type == LSA_TYPE_LINK_OPAQ) { 622097ed198Sclaudio /* 623097ed198Sclaudio * Flood on interface only 624097ed198Sclaudio */ 625097ed198Sclaudio noack += lsa_flood(nbr->iface, nbr, 626097ed198Sclaudio &lsa_hdr, imsg.data); 627204df0f8Sclaudio } else { 628204df0f8Sclaudio /* 629d165a0eeSclaudio * Flood on all area interfaces. For 630d165a0eeSclaudio * area 0.0.0.0 include the virtual links. 631204df0f8Sclaudio */ 632204df0f8Sclaudio area = nbr->iface->area; 633204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 634204df0f8Sclaudio noack += lsa_flood(iface, nbr, 63559eccb25Snorby &lsa_hdr, imsg.data); 636204df0f8Sclaudio } 637204df0f8Sclaudio /* XXX virtual links */ 638204df0f8Sclaudio } 639204df0f8Sclaudio 640204df0f8Sclaudio /* remove from ls_req_list */ 641204df0f8Sclaudio le = ls_req_list_get(nbr, &lsa_hdr); 642204df0f8Sclaudio if (!(nbr->state & NBR_STA_FULL) && le != NULL) { 643204df0f8Sclaudio ls_req_list_free(nbr, le); 644e2993955Sclaudio /* 645e2993955Sclaudio * XXX no need to ack requested lsa 646e2993955Sclaudio * the problem is that the RFC is very 647e2993955Sclaudio * unclear about this. 648e2993955Sclaudio */ 649204df0f8Sclaudio noack = 1; 650204df0f8Sclaudio } 651204df0f8Sclaudio 652e2993955Sclaudio if (!noack && nbr->iface != NULL && 653e2993955Sclaudio nbr->iface->self != nbr) { 654204df0f8Sclaudio if (!(nbr->iface->state & IF_STA_BACKUP) || 655204df0f8Sclaudio nbr->iface->dr == nbr) { 656204df0f8Sclaudio /* delayed ack */ 657204df0f8Sclaudio lhp = lsa_hdr_new(); 658204df0f8Sclaudio memcpy(lhp, &lsa_hdr, sizeof(*lhp)); 659204df0f8Sclaudio ls_ack_list_add(nbr->iface, lhp); 660204df0f8Sclaudio } 661204df0f8Sclaudio } 662204df0f8Sclaudio 663204df0f8Sclaudio lsa_cache_put(ref, nbr); 664204df0f8Sclaudio break; 665204df0f8Sclaudio case IMSG_LS_UPD: 666c983ff94Smarkus case IMSG_LS_SNAP: 667204df0f8Sclaudio /* 668c983ff94Smarkus * IMSG_LS_UPD is used in two cases: 669204df0f8Sclaudio * 1. as response to ls requests 670204df0f8Sclaudio * 2. as response to ls updates where the DB 671204df0f8Sclaudio * is newer then the sent LSA 672c983ff94Smarkus * IMSG_LS_SNAP is used in one case: 673c983ff94Smarkus * in EXSTART when the LSA has age MaxAge 674204df0f8Sclaudio */ 675204df0f8Sclaudio l = imsg.hdr.len - IMSG_HEADER_SIZE; 676204df0f8Sclaudio if (l < sizeof(lsa_hdr)) 677204df0f8Sclaudio fatalx("ospfe_dispatch_rde: " 678204df0f8Sclaudio "bad imsg size"); 679204df0f8Sclaudio 680204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 681204df0f8Sclaudio if (nbr == NULL) 6828b1d5e52Sclaudio break; 683204df0f8Sclaudio 684204df0f8Sclaudio if (nbr->iface->self == nbr) 685204df0f8Sclaudio break; 686204df0f8Sclaudio 687c983ff94Smarkus if (imsg.hdr.type == IMSG_LS_SNAP && 688c983ff94Smarkus nbr->state != NBR_STA_SNAP) 689c983ff94Smarkus break; 690c983ff94Smarkus 691204df0f8Sclaudio memcpy(&age, imsg.data, sizeof(age)); 692204df0f8Sclaudio ref = lsa_cache_add(imsg.data, l); 69332a640a4Sclaudio if (ntohs(age) >= MAX_AGE) 69432a640a4Sclaudio /* add to retransmit list */ 69532a640a4Sclaudio ls_retrans_list_add(nbr, imsg.data, 0, 0); 69632a640a4Sclaudio else 69732a640a4Sclaudio ls_retrans_list_add(nbr, imsg.data, 0, 1); 698204df0f8Sclaudio 69932a640a4Sclaudio lsa_cache_put(ref, nbr); 700204df0f8Sclaudio break; 701204df0f8Sclaudio case IMSG_LS_ACK: 702204df0f8Sclaudio /* 703204df0f8Sclaudio * IMSG_LS_ACK is used in two cases: 704204df0f8Sclaudio * 1. LSA was a duplicate 705611e3786Sclaudio * 2. LS age is MaxAge and there is no current 706c67f9065Sclaudio * instance in the DB plus no neighbor in state 707204df0f8Sclaudio * Exchange or Loading 708204df0f8Sclaudio */ 709204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 710204df0f8Sclaudio if (nbr == NULL) 7118b1d5e52Sclaudio break; 712204df0f8Sclaudio 713204df0f8Sclaudio if (nbr->iface->self == nbr) 714204df0f8Sclaudio break; 715204df0f8Sclaudio 7168adf5137Sclaudio if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr)) 7178adf5137Sclaudio fatalx("ospfe_dispatch_rde: bad imsg size"); 7188adf5137Sclaudio memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 7198adf5137Sclaudio 7208adf5137Sclaudio /* for case one check for implied acks */ 7218adf5137Sclaudio if (nbr->iface->state & IF_STA_DROTHER) 7228adf5137Sclaudio if (ls_retrans_list_del(nbr->iface->self, 7238adf5137Sclaudio &lsa_hdr) == 0) 7248adf5137Sclaudio break; 7258adf5137Sclaudio if (ls_retrans_list_del(nbr, &lsa_hdr) == 0) 7268adf5137Sclaudio break; 727204df0f8Sclaudio 728204df0f8Sclaudio /* send a direct acknowledgement */ 72962d04914Sclaudio send_direct_ack(nbr->iface, nbr->addr, imsg.data, 730204df0f8Sclaudio imsg.hdr.len - IMSG_HEADER_SIZE); 731204df0f8Sclaudio 732204df0f8Sclaudio break; 733204df0f8Sclaudio case IMSG_LS_BADREQ: 734204df0f8Sclaudio nbr = nbr_find_peerid(imsg.hdr.peerid); 735204df0f8Sclaudio if (nbr == NULL) 7368b1d5e52Sclaudio break; 737204df0f8Sclaudio 738204df0f8Sclaudio if (nbr->iface->self == nbr) 739204df0f8Sclaudio fatalx("ospfe_dispatch_rde: " 740204df0f8Sclaudio "dummy neighbor got BADREQ"); 741204df0f8Sclaudio 742204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ); 743204df0f8Sclaudio break; 744a59bf5b7Snorby case IMSG_ABR_UP: 745a59bf5b7Snorby memcpy(&ar, imsg.data, sizeof(ar)); 746a59bf5b7Snorby 747a59bf5b7Snorby if ((iface = find_vlink(&ar)) != NULL && 748a59bf5b7Snorby iface->state == IF_STA_DOWN) 749a59bf5b7Snorby if (if_fsm(iface, IF_EVT_UP)) { 750a59bf5b7Snorby log_debug("error starting interface %s", 751a59bf5b7Snorby iface->name); 752a59bf5b7Snorby } 753a59bf5b7Snorby break; 754a59bf5b7Snorby case IMSG_ABR_DOWN: 755a59bf5b7Snorby memcpy(&ar, imsg.data, sizeof(ar)); 756a59bf5b7Snorby 757a59bf5b7Snorby if ((iface = find_vlink(&ar)) != NULL && 758a59bf5b7Snorby iface->state == IF_STA_POINTTOPOINT) 759a59bf5b7Snorby if (if_fsm(iface, IF_EVT_DOWN)) { 760a59bf5b7Snorby log_debug("error stopping interface %s", 761a59bf5b7Snorby iface->name); 762a59bf5b7Snorby } 763a59bf5b7Snorby break; 764204df0f8Sclaudio case IMSG_CTL_AREA: 765097ed198Sclaudio case IMSG_CTL_IFACE: 766204df0f8Sclaudio case IMSG_CTL_END: 76759df52c7Snorby case IMSG_CTL_SHOW_DATABASE: 76832286112Snorby case IMSG_CTL_SHOW_DB_EXT: 76932286112Snorby case IMSG_CTL_SHOW_DB_NET: 77032286112Snorby case IMSG_CTL_SHOW_DB_RTR: 77132286112Snorby case IMSG_CTL_SHOW_DB_SELF: 77232286112Snorby case IMSG_CTL_SHOW_DB_SUM: 77332286112Snorby case IMSG_CTL_SHOW_DB_ASBR: 774097ed198Sclaudio case IMSG_CTL_SHOW_DB_OPAQ: 77559df52c7Snorby case IMSG_CTL_SHOW_RIB: 77659df52c7Snorby case IMSG_CTL_SHOW_SUM: 77759df52c7Snorby case IMSG_CTL_SHOW_SUM_AREA: 778204df0f8Sclaudio control_imsg_relay(&imsg); 779204df0f8Sclaudio break; 780204df0f8Sclaudio default: 781204df0f8Sclaudio log_debug("ospfe_dispatch_rde: error handling imsg %d", 782204df0f8Sclaudio imsg.hdr.type); 783204df0f8Sclaudio break; 784204df0f8Sclaudio } 785204df0f8Sclaudio imsg_free(&imsg); 786204df0f8Sclaudio } 787410c7411Sclaudio if (!shut) 7887b4c0c10Seric imsg_event_add(iev); 789410c7411Sclaudio else { 790410c7411Sclaudio /* this pipe is dead, so remove the event handler */ 7917b4c0c10Seric event_del(&iev->ev); 792410c7411Sclaudio event_loopexit(NULL); 793410c7411Sclaudio } 794204df0f8Sclaudio } 795204df0f8Sclaudio 796a59bf5b7Snorby struct iface * 797a59bf5b7Snorby find_vlink(struct abr_rtr *ar) 798a59bf5b7Snorby { 799a59bf5b7Snorby struct area *area; 800a59bf5b7Snorby struct iface *iface = NULL; 801a59bf5b7Snorby 802a59bf5b7Snorby LIST_FOREACH(area, &oeconf->area_list, entry) 803a59bf5b7Snorby LIST_FOREACH(iface, &area->iface_list, entry) 804a59bf5b7Snorby if (iface->abr_id.s_addr == ar->abr_id.s_addr && 805a59bf5b7Snorby iface->type == IF_TYPE_VIRTUALLINK && 806a59bf5b7Snorby iface->area->id.s_addr == ar->area.s_addr) { 807a59bf5b7Snorby iface->dst.s_addr = ar->dst_ip.s_addr; 808a59bf5b7Snorby iface->addr.s_addr = ar->addr.s_addr; 809aaff02a3Snorby iface->metric = ar->metric; 810a59bf5b7Snorby 811a59bf5b7Snorby return (iface); 812a59bf5b7Snorby } 813a59bf5b7Snorby 814a59bf5b7Snorby return (iface); 815a59bf5b7Snorby } 816a59bf5b7Snorby 817204df0f8Sclaudio void 818317d560cSclaudio orig_rtr_lsa_all(struct area *area) 819317d560cSclaudio { 820317d560cSclaudio struct area *a; 821317d560cSclaudio 822317d560cSclaudio /* 823317d560cSclaudio * update all router LSA in all areas except area itself, 824317d560cSclaudio * as this update is already running. 825317d560cSclaudio */ 826317d560cSclaudio LIST_FOREACH(a, &oeconf->area_list, entry) 827317d560cSclaudio if (a != area) 828317d560cSclaudio orig_rtr_lsa(a); 829317d560cSclaudio } 830317d560cSclaudio 831317d560cSclaudio void 832204df0f8Sclaudio orig_rtr_lsa(struct area *area) 833204df0f8Sclaudio { 83491cc1f69Sclaudio struct lsa_hdr lsa_hdr; 83591cc1f69Sclaudio struct lsa_rtr lsa_rtr; 83691cc1f69Sclaudio struct lsa_rtr_link rtr_link; 837204df0f8Sclaudio struct iface *iface; 838e39620e5Snicm struct ibuf *buf; 83991cc1f69Sclaudio struct nbr *nbr, *self = NULL; 84091cc1f69Sclaudio u_int16_t num_links = 0; 84191cc1f69Sclaudio u_int16_t chksum; 84293f3f85cSnorby u_int8_t border, virtual = 0; 843204df0f8Sclaudio 844204df0f8Sclaudio log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id)); 845204df0f8Sclaudio 8466860b38aSclaudio if ((buf = ibuf_dynamic(sizeof(lsa_hdr), 8476860b38aSclaudio IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) - 8486860b38aSclaudio sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL) 849204df0f8Sclaudio fatal("orig_rtr_lsa"); 850204df0f8Sclaudio 85191cc1f69Sclaudio /* reserve space for LSA header and LSA Router header */ 85243e70bb4Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_hdr)) == -1) 85343e70bb4Sclaudio fatal("orig_rtr_lsa: ibuf_add_zero failed"); 85491cc1f69Sclaudio 85543e70bb4Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_rtr)) == -1) 85643e70bb4Sclaudio fatal("orig_rtr_lsa: ibuf_add_zero failed"); 857204df0f8Sclaudio 858204df0f8Sclaudio /* links */ 859204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) { 86091cc1f69Sclaudio if (self == NULL && iface->self != NULL) 86191cc1f69Sclaudio self = iface->self; 86291cc1f69Sclaudio 86391cc1f69Sclaudio bzero(&rtr_link, sizeof(rtr_link)); 86491cc1f69Sclaudio 86591cc1f69Sclaudio if (iface->state & IF_STA_LOOPBACK) { 86691cc1f69Sclaudio rtr_link.id = iface->addr.s_addr; 86791cc1f69Sclaudio rtr_link.data = 0xffffffff; 86891cc1f69Sclaudio rtr_link.type = LINK_TYPE_STUB_NET; 86917a98f42Snorby rtr_link.metric = htons(iface->metric); 87091cc1f69Sclaudio num_links++; 871e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 8727154916cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 87391cc1f69Sclaudio continue; 87491cc1f69Sclaudio } 87591cc1f69Sclaudio 876204df0f8Sclaudio switch (iface->type) { 877204df0f8Sclaudio case IF_TYPE_POINTOPOINT: 87891cc1f69Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) 87991cc1f69Sclaudio if (nbr != iface->self && 88091cc1f69Sclaudio nbr->state & NBR_STA_FULL) 881204df0f8Sclaudio break; 88291cc1f69Sclaudio if (nbr) { 88391cc1f69Sclaudio log_debug("orig_rtr_lsa: point-to-point, " 88491cc1f69Sclaudio "interface %s", iface->name); 8855b6c72e9Snorby rtr_link.id = nbr->id.s_addr; 88691cc1f69Sclaudio rtr_link.data = iface->addr.s_addr; 88791cc1f69Sclaudio rtr_link.type = LINK_TYPE_POINTTOPOINT; 8881891964aSclaudio /* RFC 3137: stub router support */ 8891891964aSclaudio if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER || 8901891964aSclaudio oe_nofib) 8914a983288Sclaudio rtr_link.metric = MAX_METRIC; 892ac149fe2Sremi else if (iface->dependon[0] != '\0' && 893ac149fe2Sremi iface->depend_ok == 0) 894ac149fe2Sremi rtr_link.metric = MAX_METRIC; 8951891964aSclaudio else 89691cc1f69Sclaudio rtr_link.metric = htons(iface->metric); 89791cc1f69Sclaudio num_links++; 898e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 8997154916cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 90091cc1f69Sclaudio } 9017b5ae6e3Sremi if ((iface->flags & IFF_UP) && 9027b5ae6e3Sremi LINK_STATE_IS_UP(iface->linkstate)) { 903204df0f8Sclaudio log_debug("orig_rtr_lsa: stub net, " 904204df0f8Sclaudio "interface %s", iface->name); 90591cc1f69Sclaudio bzero(&rtr_link, sizeof(rtr_link)); 90691cc1f69Sclaudio if (nbr) { 90791cc1f69Sclaudio rtr_link.id = nbr->addr.s_addr; 90891cc1f69Sclaudio rtr_link.data = 0xffffffff; 909204df0f8Sclaudio } else { 910f1049baeSremi rtr_link.id = iface->addr.s_addr & 911f1049baeSremi iface->mask.s_addr; 91291cc1f69Sclaudio rtr_link.data = iface->mask.s_addr; 91391cc1f69Sclaudio } 91491cc1f69Sclaudio rtr_link.type = LINK_TYPE_STUB_NET; 9157b5ae6e3Sremi if (iface->dependon[0] != '\0' && 9167b5ae6e3Sremi iface->depend_ok == 0) 9177b5ae6e3Sremi rtr_link.metric = MAX_METRIC; 9187b5ae6e3Sremi else 9191891964aSclaudio rtr_link.metric = htons(iface->metric); 92091cc1f69Sclaudio num_links++; 921e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 9227154916cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 92391cc1f69Sclaudio } 92491cc1f69Sclaudio continue; 92591cc1f69Sclaudio case IF_TYPE_BROADCAST: 92691cc1f69Sclaudio case IF_TYPE_NBMA: 92791cc1f69Sclaudio if ((iface->state & IF_STA_MULTI)) { 92891cc1f69Sclaudio if (iface->dr == iface->self) { 92991cc1f69Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, 93091cc1f69Sclaudio entry) 93191cc1f69Sclaudio if (nbr != iface->self && 93291cc1f69Sclaudio nbr->state & NBR_STA_FULL) 93391cc1f69Sclaudio break; 93491cc1f69Sclaudio } else 93591cc1f69Sclaudio nbr = iface->dr; 93691cc1f69Sclaudio 93791cc1f69Sclaudio if (nbr && nbr->state & NBR_STA_FULL) { 938204df0f8Sclaudio log_debug("orig_rtr_lsa: transit net, " 939204df0f8Sclaudio "interface %s", iface->name); 940204df0f8Sclaudio 94191cc1f69Sclaudio rtr_link.id = iface->dr->addr.s_addr; 94291cc1f69Sclaudio rtr_link.data = iface->addr.s_addr; 94391cc1f69Sclaudio rtr_link.type = LINK_TYPE_TRANSIT_NET; 944204df0f8Sclaudio break; 94591cc1f69Sclaudio } 94691cc1f69Sclaudio } 947d7a91d7eSclaudio 948fac689dcSclaudio /* 949fac689dcSclaudio * do not add a stub net LSA for interfaces that are: 950fac689dcSclaudio * - down 951db8be643Ssthen * - have a linkstate which is down, apart from carp: 952db8be643Ssthen * backup carp interfaces have linkstate down, but 953db8be643Ssthen * we still announce them. 954fac689dcSclaudio */ 955fac689dcSclaudio if (!(iface->flags & IFF_UP) || 956db8be643Ssthen (!LINK_STATE_IS_UP(iface->linkstate) && 95718ffdd94Sstsp !(iface->if_type == IFT_CARP && 958db8be643Ssthen iface->linkstate == LINK_STATE_DOWN))) 959d7a91d7eSclaudio continue; 96091cc1f69Sclaudio log_debug("orig_rtr_lsa: stub net, " 96191cc1f69Sclaudio "interface %s", iface->name); 96291cc1f69Sclaudio 96391cc1f69Sclaudio rtr_link.id = 96491cc1f69Sclaudio iface->addr.s_addr & iface->mask.s_addr; 96591cc1f69Sclaudio rtr_link.data = iface->mask.s_addr; 96691cc1f69Sclaudio rtr_link.type = LINK_TYPE_STUB_NET; 967fac689dcSclaudio 968fac689dcSclaudio rtr_link.num_tos = 0; 969fac689dcSclaudio /* 970ac149fe2Sremi * backup carp interfaces and interfaces that depend 971ac149fe2Sremi * on an interface that is down are announced with 972ac149fe2Sremi * high metric for faster failover. 973fac689dcSclaudio */ 97418ffdd94Sstsp if (iface->if_type == IFT_CARP && 975fac689dcSclaudio iface->linkstate == LINK_STATE_DOWN) 976fac689dcSclaudio rtr_link.metric = MAX_METRIC; 977ac149fe2Sremi else if (iface->dependon[0] != '\0' && 978ac149fe2Sremi iface->depend_ok == 0) 979ac149fe2Sremi rtr_link.metric = MAX_METRIC; 980fac689dcSclaudio else 981fac689dcSclaudio rtr_link.metric = htons(iface->metric); 982fac689dcSclaudio num_links++; 983e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 984e39620e5Snicm fatalx("orig_rtr_lsa: ibuf_add failed"); 985fac689dcSclaudio continue; 98691cc1f69Sclaudio case IF_TYPE_VIRTUALLINK: 987aaff02a3Snorby LIST_FOREACH(nbr, &iface->nbr_list, entry) { 988aaff02a3Snorby if (nbr != iface->self && 989aaff02a3Snorby nbr->state & NBR_STA_FULL) 990aaff02a3Snorby break; 991aaff02a3Snorby } 992aaff02a3Snorby if (nbr) { 993aaff02a3Snorby rtr_link.id = nbr->id.s_addr; 994aaff02a3Snorby rtr_link.data = iface->addr.s_addr; 995aaff02a3Snorby rtr_link.type = LINK_TYPE_VIRTUAL; 9961891964aSclaudio /* RFC 3137: stub router support */ 9971891964aSclaudio if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER || 9981891964aSclaudio oe_nofib) 9994a983288Sclaudio rtr_link.metric = MAX_METRIC; 10001891964aSclaudio else 1001aaff02a3Snorby rtr_link.metric = htons(iface->metric); 1002aaff02a3Snorby num_links++; 100393f3f85cSnorby virtual = 1; 1004e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 1005e39620e5Snicm fatalx("orig_rtr_lsa: ibuf_add failed"); 1006aaff02a3Snorby 1007d7a91d7eSclaudio log_debug("orig_rtr_lsa: virtual link, " 1008d7a91d7eSclaudio "interface %s", iface->name); 1009aaff02a3Snorby } 101091cc1f69Sclaudio continue; 101191cc1f69Sclaudio case IF_TYPE_POINTOMULTIPOINT: 101291cc1f69Sclaudio log_debug("orig_rtr_lsa: stub net, " 101391cc1f69Sclaudio "interface %s", iface->name); 101491cc1f69Sclaudio rtr_link.id = iface->addr.s_addr; 101591cc1f69Sclaudio rtr_link.data = 0xffffffff; 101691cc1f69Sclaudio rtr_link.type = LINK_TYPE_STUB_NET; 10171891964aSclaudio rtr_link.metric = htons(iface->metric); 101891cc1f69Sclaudio num_links++; 1019e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 1020e39620e5Snicm fatalx("orig_rtr_lsa: ibuf_add failed"); 102191cc1f69Sclaudio 102291cc1f69Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 102391cc1f69Sclaudio if (nbr != iface->self && 102491cc1f69Sclaudio nbr->state & NBR_STA_FULL) { 102591cc1f69Sclaudio bzero(&rtr_link, sizeof(rtr_link)); 102691cc1f69Sclaudio log_debug("orig_rtr_lsa: " 10271891964aSclaudio "point-to-multipoint, interface %s", 102891cc1f69Sclaudio iface->name); 102991cc1f69Sclaudio rtr_link.id = nbr->addr.s_addr; 103091cc1f69Sclaudio rtr_link.data = iface->addr.s_addr; 103191cc1f69Sclaudio rtr_link.type = LINK_TYPE_POINTTOPOINT; 10321891964aSclaudio /* RFC 3137: stub router support */ 10331891964aSclaudio if (oe_nofib || oeconf->flags & 10341891964aSclaudio OSPFD_FLAG_STUB_ROUTER) 10354a983288Sclaudio rtr_link.metric = MAX_METRIC; 1036ac149fe2Sremi else if (iface->dependon[0] != '\0' && 1037ac149fe2Sremi iface->depend_ok == 0) 1038ac149fe2Sremi rtr_link.metric = MAX_METRIC; 10391891964aSclaudio else 10401891964aSclaudio rtr_link.metric = 10411891964aSclaudio htons(iface->metric); 104291cc1f69Sclaudio num_links++; 1043e39620e5Snicm if (ibuf_add(buf, &rtr_link, 104491cc1f69Sclaudio sizeof(rtr_link))) 104591cc1f69Sclaudio fatalx("orig_rtr_lsa: " 1046e39620e5Snicm "ibuf_add failed"); 104791cc1f69Sclaudio } 104891cc1f69Sclaudio } 104991cc1f69Sclaudio continue; 1050204df0f8Sclaudio default: 1051204df0f8Sclaudio fatalx("orig_rtr_lsa: unknown interface type"); 1052204df0f8Sclaudio } 105391cc1f69Sclaudio 105491cc1f69Sclaudio rtr_link.num_tos = 0; 10551891964aSclaudio /* RFC 3137: stub router support */ 10561891964aSclaudio if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER || oe_nofib) && 10571891964aSclaudio rtr_link.type != LINK_TYPE_STUB_NET) 10584a983288Sclaudio rtr_link.metric = MAX_METRIC; 1059e153091cSdlg else if (iface->dependon[0] != '\0' && iface->depend_ok == 0) 1060e153091cSdlg rtr_link.metric = MAX_METRIC; 10611891964aSclaudio else 106291cc1f69Sclaudio rtr_link.metric = htons(iface->metric); 106391cc1f69Sclaudio num_links++; 1064e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 1065e39620e5Snicm fatalx("orig_rtr_lsa: ibuf_add failed"); 1066204df0f8Sclaudio } 1067204df0f8Sclaudio 106891cc1f69Sclaudio /* LSA router header */ 1069e2993955Sclaudio lsa_rtr.flags = 0; 1070e2993955Sclaudio /* 1071e2993955Sclaudio * Set the E bit as soon as an as-ext lsa may be redistributed, only 1072e2993955Sclaudio * setting it in case we redistribute something is not worth the fuss. 107398b447a7Sclaudio * Do not set the E bit in case of a stub area. 1074e2993955Sclaudio */ 10753ffd5c19Sclaudio if (oeconf->redistribute && !area->stub) 1076e2993955Sclaudio lsa_rtr.flags |= OSPF_RTR_E; 1077317d560cSclaudio 1078970e0104Sclaudio border = (area_border_router(oeconf) != 0); 1079317d560cSclaudio if (border != oeconf->border) { 1080317d560cSclaudio oeconf->border = border; 1081317d560cSclaudio orig_rtr_lsa_all(area); 1082317d560cSclaudio } 1083317d560cSclaudio if (oeconf->border) 1084317d560cSclaudio lsa_rtr.flags |= OSPF_RTR_B; 108506267228Sclaudio 10861891964aSclaudio /* TODO set V flag if a active virtual link ends here and the 1087cc63418dSsthen * area is the transit area for this link. */ 108893f3f85cSnorby if (virtual) 108993f3f85cSnorby lsa_rtr.flags |= OSPF_RTR_V; 1090317d560cSclaudio 109191cc1f69Sclaudio lsa_rtr.dummy = 0; 109291cc1f69Sclaudio lsa_rtr.nlinks = htons(num_links); 109343e70bb4Sclaudio if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_rtr, sizeof(lsa_rtr)) == 109443e70bb4Sclaudio -1) 109543e70bb4Sclaudio fatal("orig_rtr_lsa: ibuf_set failed"); 1096204df0f8Sclaudio 109791cc1f69Sclaudio /* LSA header */ 109891cc1f69Sclaudio lsa_hdr.age = htons(DEFAULT_AGE); 10993ffd5c19Sclaudio lsa_hdr.opts = area_ospf_options(area); 110091cc1f69Sclaudio lsa_hdr.type = LSA_TYPE_ROUTER; 110191cc1f69Sclaudio lsa_hdr.ls_id = oeconf->rtr_id.s_addr; 110291cc1f69Sclaudio lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 110391cc1f69Sclaudio lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1104e39620e5Snicm lsa_hdr.len = htons(ibuf_size(buf)); 110591cc1f69Sclaudio lsa_hdr.ls_chksum = 0; /* updated later */ 110643e70bb4Sclaudio if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1) 110743e70bb4Sclaudio fatal("orig_rtr_lsa: ibuf_set failed"); 1108204df0f8Sclaudio 1109a50d52cbSclaudio chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET); 111043e70bb4Sclaudio if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1) 111143e70bb4Sclaudio fatal("orig_rtr_lsa: ibuf_set_n16 failed"); 1112204df0f8Sclaudio 111342a0f593Smarkus if (self && num_links) 11147b4c0c10Seric imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0, 1115a50d52cbSclaudio -1, ibuf_data(buf), ibuf_size(buf)); 111691cc1f69Sclaudio else 111791cc1f69Sclaudio log_warnx("orig_rtr_lsa: empty area %s", 111891cc1f69Sclaudio inet_ntoa(area->id)); 111991cc1f69Sclaudio 1120e39620e5Snicm ibuf_free(buf); 1121204df0f8Sclaudio } 1122204df0f8Sclaudio 1123204df0f8Sclaudio void 1124204df0f8Sclaudio orig_net_lsa(struct iface *iface) 1125204df0f8Sclaudio { 112691cc1f69Sclaudio struct lsa_hdr lsa_hdr; 1127204df0f8Sclaudio struct nbr *nbr; 1128e39620e5Snicm struct ibuf *buf; 1129204df0f8Sclaudio int num_rtr = 0; 113091cc1f69Sclaudio u_int16_t chksum; 1131204df0f8Sclaudio 11326860b38aSclaudio if ((buf = ibuf_dynamic(sizeof(lsa_hdr), 11336860b38aSclaudio IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) - 11346860b38aSclaudio sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL) 1135204df0f8Sclaudio fatal("orig_net_lsa"); 1136204df0f8Sclaudio 113791cc1f69Sclaudio /* reserve space for LSA header and LSA Router header */ 113843e70bb4Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_hdr)) == -1) 113943e70bb4Sclaudio fatal("orig_net_lsa: ibuf_add_zero failed"); 1140204df0f8Sclaudio 114191cc1f69Sclaudio /* LSA net mask and then all fully adjacent routers */ 1142e39620e5Snicm if (ibuf_add(buf, &iface->mask, sizeof(iface->mask))) 1143e39620e5Snicm fatal("orig_net_lsa: ibuf_add failed"); 1144204df0f8Sclaudio 1145204df0f8Sclaudio /* fully adjacent neighbors + self */ 114691cc1f69Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) 114791cc1f69Sclaudio if (nbr->state & NBR_STA_FULL) { 1148e39620e5Snicm if (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 1149e39620e5Snicm fatal("orig_net_lsa: ibuf_add failed"); 1150204df0f8Sclaudio num_rtr++; 1151204df0f8Sclaudio } 1152204df0f8Sclaudio 115391cc1f69Sclaudio if (num_rtr == 1) { 1154cc63418dSsthen /* non transit net therefore no need to generate a net lsa */ 1155e39620e5Snicm ibuf_free(buf); 115691cc1f69Sclaudio return; 115791cc1f69Sclaudio } 1158204df0f8Sclaudio 115991cc1f69Sclaudio /* LSA header */ 116091cc1f69Sclaudio if (iface->state & IF_STA_DR) 116191cc1f69Sclaudio lsa_hdr.age = htons(DEFAULT_AGE); 116291cc1f69Sclaudio else 116391cc1f69Sclaudio lsa_hdr.age = htons(MAX_AGE); 116491cc1f69Sclaudio 11653ffd5c19Sclaudio lsa_hdr.opts = area_ospf_options(iface->area); 116691cc1f69Sclaudio lsa_hdr.type = LSA_TYPE_NETWORK; 116791cc1f69Sclaudio lsa_hdr.ls_id = iface->addr.s_addr; 116891cc1f69Sclaudio lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 116991cc1f69Sclaudio lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1170e39620e5Snicm lsa_hdr.len = htons(ibuf_size(buf)); 117191cc1f69Sclaudio lsa_hdr.ls_chksum = 0; /* updated later */ 117243e70bb4Sclaudio if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1) 117343e70bb4Sclaudio fatal("orig_net_lsa: ibuf_set failed"); 117491cc1f69Sclaudio 1175a50d52cbSclaudio chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET); 117643e70bb4Sclaudio if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1) 117743e70bb4Sclaudio fatal("orig_net_lsa: ibuf_set_n16 failed"); 117891cc1f69Sclaudio 11797b4c0c10Seric imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0, 1180a50d52cbSclaudio -1, ibuf_data(buf), ibuf_size(buf)); 118191cc1f69Sclaudio 1182e39620e5Snicm ibuf_free(buf); 1183204df0f8Sclaudio } 1184204df0f8Sclaudio 1185204df0f8Sclaudio u_int32_t 1186204df0f8Sclaudio ospfe_router_id(void) 1187204df0f8Sclaudio { 1188204df0f8Sclaudio return (oeconf->rtr_id.s_addr); 1189204df0f8Sclaudio } 1190204df0f8Sclaudio 1191204df0f8Sclaudio void 1192faec9e2bSclaudio ospfe_fib_update(int type) 11931891964aSclaudio { 11941891964aSclaudio int old = oe_nofib; 11951891964aSclaudio 11961891964aSclaudio if (type == IMSG_CTL_FIB_COUPLE) 11971891964aSclaudio oe_nofib = 0; 11981891964aSclaudio if (type == IMSG_CTL_FIB_DECOUPLE) 11991891964aSclaudio oe_nofib = 1; 12001891964aSclaudio if (old != oe_nofib) 12011891964aSclaudio orig_rtr_lsa_all(NULL); 12021891964aSclaudio } 12031891964aSclaudio 12041891964aSclaudio void 1205204df0f8Sclaudio ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx) 1206204df0f8Sclaudio { 1207204df0f8Sclaudio struct area *area; 1208204df0f8Sclaudio struct iface *iface; 1209204df0f8Sclaudio struct ctl_iface *ictl; 1210204df0f8Sclaudio 1211204df0f8Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) 1212204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) 1213204df0f8Sclaudio if (idx == 0 || idx == iface->ifindex) { 1214204df0f8Sclaudio ictl = if_to_ctl(iface); 12157154916cSclaudio imsg_compose_event(&c->iev, 12167154916cSclaudio IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 12177154916cSclaudio ictl, sizeof(struct ctl_iface)); 1218204df0f8Sclaudio } 1219204df0f8Sclaudio } 1220204df0f8Sclaudio 1221204df0f8Sclaudio void 1222204df0f8Sclaudio ospfe_nbr_ctl(struct ctl_conn *c) 1223204df0f8Sclaudio { 1224204df0f8Sclaudio struct area *area; 1225204df0f8Sclaudio struct iface *iface; 1226204df0f8Sclaudio struct nbr *nbr; 1227204df0f8Sclaudio struct ctl_nbr *nctl; 1228204df0f8Sclaudio 1229204df0f8Sclaudio LIST_FOREACH(area, &oeconf->area_list, entry) 1230204df0f8Sclaudio LIST_FOREACH(iface, &area->iface_list, entry) 1231204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 1232204df0f8Sclaudio if (iface->self != nbr) { 1233204df0f8Sclaudio nctl = nbr_to_ctl(nbr); 12347b4c0c10Seric imsg_compose_event(&c->iev, 1235d13e54e1Spyr IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, 1236204df0f8Sclaudio sizeof(struct ctl_nbr)); 1237204df0f8Sclaudio } 1238204df0f8Sclaudio } 1239204df0f8Sclaudio 12407b4c0c10Seric imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 1241204df0f8Sclaudio } 1242fba2d3d0Sclaudio 1243fba2d3d0Sclaudio void 1244fba2d3d0Sclaudio ospfe_demote_area(struct area *area, int active) 1245fba2d3d0Sclaudio { 1246fba2d3d0Sclaudio struct demote_msg dmsg; 1247fba2d3d0Sclaudio 1248fba2d3d0Sclaudio if (ospfd_process != PROC_OSPF_ENGINE || 1249fba2d3d0Sclaudio area->demote_group[0] == '\0') 1250fba2d3d0Sclaudio return; 1251fba2d3d0Sclaudio 1252fba2d3d0Sclaudio bzero(&dmsg, sizeof(dmsg)); 1253fba2d3d0Sclaudio strlcpy(dmsg.demote_group, area->demote_group, 1254fba2d3d0Sclaudio sizeof(dmsg.demote_group)); 1255fba2d3d0Sclaudio dmsg.level = area->demote_level; 1256fba2d3d0Sclaudio if (active) 1257fba2d3d0Sclaudio dmsg.level = -dmsg.level; 1258fba2d3d0Sclaudio 1259fba2d3d0Sclaudio ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1260fba2d3d0Sclaudio } 1261fba2d3d0Sclaudio 1262fba2d3d0Sclaudio void 1263fba2d3d0Sclaudio ospfe_demote_iface(struct iface *iface, int active) 1264fba2d3d0Sclaudio { 1265fba2d3d0Sclaudio struct demote_msg dmsg; 1266fba2d3d0Sclaudio 1267fba2d3d0Sclaudio if (ospfd_process != PROC_OSPF_ENGINE || 1268fba2d3d0Sclaudio iface->demote_group[0] == '\0') 1269fba2d3d0Sclaudio return; 1270fba2d3d0Sclaudio 1271fba2d3d0Sclaudio bzero(&dmsg, sizeof(dmsg)); 1272fba2d3d0Sclaudio strlcpy(dmsg.demote_group, iface->demote_group, 1273fba2d3d0Sclaudio sizeof(dmsg.demote_group)); 1274fba2d3d0Sclaudio if (active) 1275fba2d3d0Sclaudio dmsg.level = -1; 1276fba2d3d0Sclaudio else 1277fba2d3d0Sclaudio dmsg.level = 1; 1278fba2d3d0Sclaudio 1279fac689dcSclaudio log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group, 1280fac689dcSclaudio dmsg.level); 1281fac689dcSclaudio 1282fba2d3d0Sclaudio ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1283fba2d3d0Sclaudio } 1284