1*f1b790a5Sclaudio /* $OpenBSD: ospfe.c,v 1.78 2024/11/21 13:38:14 claudio Exp $ */ 2a1a4e97bSnorby 3a1a4e97bSnorby /* 4a1a4e97bSnorby * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5a1a4e97bSnorby * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6a1a4e97bSnorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7a1a4e97bSnorby * 8a1a4e97bSnorby * Permission to use, copy, modify, and distribute this software for any 9a1a4e97bSnorby * purpose with or without fee is hereby granted, provided that the above 10a1a4e97bSnorby * copyright notice and this permission notice appear in all copies. 11a1a4e97bSnorby * 12a1a4e97bSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13a1a4e97bSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14a1a4e97bSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15a1a4e97bSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16a1a4e97bSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17a1a4e97bSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18a1a4e97bSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19a1a4e97bSnorby */ 20a1a4e97bSnorby 21a1a4e97bSnorby #include <sys/types.h> 22a1a4e97bSnorby #include <sys/socket.h> 23a1a4e97bSnorby #include <sys/queue.h> 24a1a4e97bSnorby #include <netinet/in.h> 25a1a4e97bSnorby #include <arpa/inet.h> 26a1a4e97bSnorby #include <net/if_types.h> 27a1a4e97bSnorby #include <stdlib.h> 28a1a4e97bSnorby #include <signal.h> 29a1a4e97bSnorby #include <string.h> 30a1a4e97bSnorby #include <fcntl.h> 31a1a4e97bSnorby #include <pwd.h> 32a1a4e97bSnorby #include <unistd.h> 33a1a4e97bSnorby #include <event.h> 34a1a4e97bSnorby #include <err.h> 35a1a4e97bSnorby #include <errno.h> 36a1a4e97bSnorby #include <stdio.h> 37a1a4e97bSnorby 38a1a4e97bSnorby #include "ospf6.h" 39a1a4e97bSnorby #include "ospf6d.h" 40a1a4e97bSnorby #include "ospfe.h" 41a1a4e97bSnorby #include "rde.h" 42a1a4e97bSnorby #include "control.h" 43a1a4e97bSnorby #include "log.h" 44a1a4e97bSnorby 45a1a4e97bSnorby void ospfe_sig_handler(int, short, void *); 46ee103ef4Srenato __dead void ospfe_shutdown(void); 47a1a4e97bSnorby void orig_rtr_lsa_all(struct area *); 48a1a4e97bSnorby struct iface *find_vlink(struct abr_rtr *); 49a1a4e97bSnorby 5077138d9fSclaudio struct ospfd_conf *oeconf = NULL, *noeconf; 51ccbb71f5Sclaudio static struct imsgev *iev_main; 52ccbb71f5Sclaudio static struct imsgev *iev_rde; 53a1a4e97bSnorby int oe_nofib; 54a1a4e97bSnorby 55a1a4e97bSnorby void 56a1a4e97bSnorby ospfe_sig_handler(int sig, short event, void *bula) 57a1a4e97bSnorby { 58a1a4e97bSnorby switch (sig) { 59a1a4e97bSnorby case SIGINT: 60a1a4e97bSnorby case SIGTERM: 61a1a4e97bSnorby ospfe_shutdown(); 62a1a4e97bSnorby /* NOTREACHED */ 63a1a4e97bSnorby default: 64a1a4e97bSnorby fatalx("unexpected signal"); 65a1a4e97bSnorby } 66a1a4e97bSnorby } 67a1a4e97bSnorby 68a1a4e97bSnorby /* ospf engine */ 69a1a4e97bSnorby pid_t 70a1a4e97bSnorby ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2], 71a1a4e97bSnorby int pipe_parent2rde[2]) 72a1a4e97bSnorby { 73a1a4e97bSnorby struct area *area; 74a1a4e97bSnorby struct iface *iface; 75a1a4e97bSnorby struct passwd *pw; 76a1a4e97bSnorby struct event ev_sigint, ev_sigterm; 77a1a4e97bSnorby pid_t pid; 783b835e81Sjob int pre = IPTOS_PREC_INTERNETCONTROL; 79a1a4e97bSnorby 80a1a4e97bSnorby switch (pid = fork()) { 81a1a4e97bSnorby case -1: 82a1a4e97bSnorby fatal("cannot fork"); 83a1a4e97bSnorby case 0: 84a1a4e97bSnorby break; 85a1a4e97bSnorby default: 86a1a4e97bSnorby return (pid); 87a1a4e97bSnorby } 88a1a4e97bSnorby 89a1a4e97bSnorby /* create the raw ip socket */ 9035251ca5Sclaudio if ((xconf->ospf_socket = socket(AF_INET6, 9135251ca5Sclaudio SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_OSPF)) == -1) 92a1a4e97bSnorby fatal("error creating raw socket"); 93a1a4e97bSnorby 943b835e81Sjob if (setsockopt(xconf->ospf_socket, IPPROTO_IPV6, IPV6_TCLASS, &pre, 953b835e81Sjob sizeof(pre)) == -1) 963b835e81Sjob fatal("setsockopt IPV6_TCLASS"); 973b835e81Sjob 98a1a4e97bSnorby /* set some defaults */ 99a1a4e97bSnorby if (if_set_mcast_loop(xconf->ospf_socket) == -1) 100a1a4e97bSnorby fatal("if_set_mcast_loop"); 10177b36df3Sclaudio if (if_set_ipv6_checksum(xconf->ospf_socket) == -1) 10277b36df3Sclaudio fatal("if_set_ipv6_checksum"); 10377b36df3Sclaudio if (if_set_ipv6_pktinfo(xconf->ospf_socket, 1) == -1) 10477b36df3Sclaudio fatal("if_set_ipv6_pktinfo"); 105678bb30aSdenis if_set_sockbuf(xconf->ospf_socket); 106a1a4e97bSnorby 107a1a4e97bSnorby oeconf = xconf; 108a1a4e97bSnorby if (oeconf->flags & OSPFD_FLAG_NO_FIB_UPDATE) 109a1a4e97bSnorby oe_nofib = 1; 110a1a4e97bSnorby 111a1a4e97bSnorby if ((pw = getpwnam(OSPF6D_USER)) == NULL) 112a1a4e97bSnorby fatal("getpwnam"); 113a1a4e97bSnorby 114a1a4e97bSnorby if (chroot(pw->pw_dir) == -1) 115a1a4e97bSnorby fatal("chroot"); 116a1a4e97bSnorby if (chdir("/") == -1) 117a1a4e97bSnorby fatal("chdir(\"/\")"); 118a1a4e97bSnorby 119a1a4e97bSnorby setproctitle("ospf engine"); 120189fd1ceSbenno /* 121189fd1ceSbenno * XXX needed with fork+exec 122189fd1ceSbenno * log_init(debug, LOG_DAEMON); 123189fd1ceSbenno * log_setverbose(verbose); 124189fd1ceSbenno */ 125189fd1ceSbenno 126a1a4e97bSnorby ospfd_process = PROC_OSPF_ENGINE; 127189fd1ceSbenno log_procinit(log_procnames[ospfd_process]); 128a1a4e97bSnorby 129a1a4e97bSnorby if (setgroups(1, &pw->pw_gid) || 130a1a4e97bSnorby setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 131a1a4e97bSnorby setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 132a1a4e97bSnorby fatal("can't drop privileges"); 133a1a4e97bSnorby 134cb75d791Sremi if (pledge("stdio inet mcast recvfd", NULL) == -1) 135b165ff27Sfriehm fatal("pledge"); 136b165ff27Sfriehm 137a1a4e97bSnorby event_init(); 138a1a4e97bSnorby nbr_init(NBR_HASHSIZE); 139a1a4e97bSnorby lsa_cache_init(LSA_HASHSIZE); 140a1a4e97bSnorby 141a1a4e97bSnorby /* setup signal handler */ 142a1a4e97bSnorby signal_set(&ev_sigint, SIGINT, ospfe_sig_handler, NULL); 143a1a4e97bSnorby signal_set(&ev_sigterm, SIGTERM, ospfe_sig_handler, NULL); 144a1a4e97bSnorby signal_add(&ev_sigint, NULL); 145a1a4e97bSnorby signal_add(&ev_sigterm, NULL); 146a1a4e97bSnorby signal(SIGPIPE, SIG_IGN); 147a1a4e97bSnorby signal(SIGHUP, SIG_IGN); 148a1a4e97bSnorby 149a1a4e97bSnorby /* setup pipes */ 150a1a4e97bSnorby close(pipe_parent2ospfe[0]); 151a1a4e97bSnorby close(pipe_ospfe2rde[1]); 152a1a4e97bSnorby close(pipe_parent2rde[0]); 153a1a4e97bSnorby close(pipe_parent2rde[1]); 154a1a4e97bSnorby 155f78850efSeric if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL || 156f78850efSeric (iev_main = malloc(sizeof(struct imsgev))) == NULL) 157a1a4e97bSnorby fatal(NULL); 158*f1b790a5Sclaudio if (imsgbuf_init(&iev_rde->ibuf, pipe_ospfe2rde[0]) == -1) 159*f1b790a5Sclaudio fatal(NULL); 160f78850efSeric 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); 164f78850efSeric iev_main->handler = ospfe_dispatch_main; 165a1a4e97bSnorby 166a1a4e97bSnorby /* setup event handler */ 167f78850efSeric iev_rde->events = EV_READ; 168f78850efSeric event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 169f78850efSeric iev_rde->handler, iev_rde); 170f78850efSeric event_add(&iev_rde->ev, NULL); 171a1a4e97bSnorby 172f78850efSeric iev_main->events = EV_READ; 173f78850efSeric event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 174f78850efSeric iev_main->handler, iev_main); 175f78850efSeric event_add(&iev_main->ev, NULL); 176a1a4e97bSnorby 177a1a4e97bSnorby event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST, 178a1a4e97bSnorby recv_packet, oeconf); 179a1a4e97bSnorby event_add(&oeconf->ev, NULL); 180a1a4e97bSnorby 181a1a4e97bSnorby /* remove unneeded config stuff */ 18202570afaSremi conf_clear_redist_list(&oeconf->redist_list); 183a1a4e97bSnorby 184a1a4e97bSnorby /* start interfaces */ 185a1a4e97bSnorby LIST_FOREACH(area, &oeconf->area_list, entry) { 186a1a4e97bSnorby ospfe_demote_area(area, 0); 1876c9e7a5bSclaudio LIST_FOREACH(iface, &area->iface_list, entry) 1886c9e7a5bSclaudio if_start(xconf, iface); 189a1a4e97bSnorby } 190a1a4e97bSnorby 191a1a4e97bSnorby event_dispatch(); 192a1a4e97bSnorby 193a1a4e97bSnorby ospfe_shutdown(); 194a1a4e97bSnorby /* NOTREACHED */ 195a1a4e97bSnorby return (0); 196a1a4e97bSnorby } 197a1a4e97bSnorby 198ee103ef4Srenato __dead void 199a1a4e97bSnorby ospfe_shutdown(void) 200a1a4e97bSnorby { 201a1a4e97bSnorby struct area *area; 202a1a4e97bSnorby struct iface *iface; 203a1a4e97bSnorby 204ee103ef4Srenato /* close pipes */ 205dd7efffeSclaudio imsgbuf_write(&iev_rde->ibuf); 2069cbf9e90Sclaudio imsgbuf_clear(&iev_rde->ibuf); 207ee103ef4Srenato close(iev_rde->ibuf.fd); 208dd7efffeSclaudio imsgbuf_write(&iev_main->ibuf); 2099cbf9e90Sclaudio imsgbuf_clear(&iev_main->ibuf); 210ee103ef4Srenato close(iev_main->ibuf.fd); 211ee103ef4Srenato 212a1a4e97bSnorby /* stop all interfaces and remove all areas */ 213a1a4e97bSnorby while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) { 214a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, entry) { 215a1a4e97bSnorby if (if_fsm(iface, IF_EVT_DOWN)) { 216a1a4e97bSnorby log_debug("error stopping interface %s", 217a1a4e97bSnorby iface->name); 218a1a4e97bSnorby } 219a1a4e97bSnorby } 220a1a4e97bSnorby LIST_REMOVE(area, entry); 221a1a4e97bSnorby area_del(area); 222a1a4e97bSnorby } 223a1a4e97bSnorby 224a1a4e97bSnorby close(oeconf->ospf_socket); 225a1a4e97bSnorby 226a1a4e97bSnorby /* clean up */ 227f78850efSeric free(iev_rde); 228f78850efSeric free(iev_main); 229a1a4e97bSnorby free(oeconf); 230a1a4e97bSnorby 231a1a4e97bSnorby log_info("ospf engine exiting"); 232a1a4e97bSnorby _exit(0); 233a1a4e97bSnorby } 234a1a4e97bSnorby 235a1a4e97bSnorby /* imesg */ 236a1a4e97bSnorby int 237a1a4e97bSnorby ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 238a1a4e97bSnorby { 239f78850efSeric return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 240a1a4e97bSnorby } 241a1a4e97bSnorby 242a1a4e97bSnorby int 243a1a4e97bSnorby ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, 244a1a4e97bSnorby void *data, u_int16_t datalen) 245a1a4e97bSnorby { 246f78850efSeric return (imsg_compose_event(iev_rde, type, peerid, pid, -1, 247f78850efSeric data, datalen)); 248a1a4e97bSnorby } 249a1a4e97bSnorby 250a1a4e97bSnorby void 251a1a4e97bSnorby ospfe_dispatch_main(int fd, short event, void *bula) 252a1a4e97bSnorby { 253a1a4e97bSnorby static struct area *narea; 254f11dc975Sbluhm struct area *area; 255a66c91f2Sremi struct iface *iface, *ifp, *i; 2568e1674f3Sbluhm struct ifaddrchange *ifc; 2578e1674f3Sbluhm struct iface_addr *ia, *nia; 258a1a4e97bSnorby struct imsg imsg; 259f78850efSeric struct imsgev *iev = bula; 260f78850efSeric struct imsgbuf *ibuf = &iev->ibuf; 2610dcde55eSjca int n, stub_changed, shut = 0, isvalid, wasvalid; 262a1a4e97bSnorby 26341e7b05eSclaudio if (event & EV_READ) { 264668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 265dd7efffeSclaudio fatal("imsgbuf_read error"); 266a1a4e97bSnorby if (n == 0) /* connection closed */ 267a1a4e97bSnorby shut = 1; 26841e7b05eSclaudio } 26941e7b05eSclaudio if (event & EV_WRITE) { 270dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 271c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 2721203692fSkrw shut = 1; 273c1aa9554Sclaudio else 274dd7efffeSclaudio fatal("imsgbuf_write"); 275c1aa9554Sclaudio } 276a1a4e97bSnorby } 277a1a4e97bSnorby 278a1a4e97bSnorby for (;;) { 279a1a4e97bSnorby if ((n = imsg_get(ibuf, &imsg)) == -1) 280262992b2Sclaudio fatal("ospfe_dispatch_main: imsg_get error"); 281a1a4e97bSnorby if (n == 0) 282a1a4e97bSnorby break; 283a1a4e97bSnorby 284a1a4e97bSnorby switch (imsg.hdr.type) { 285a1a4e97bSnorby case IMSG_IFINFO: 286a1a4e97bSnorby if (imsg.hdr.len != IMSG_HEADER_SIZE + 2876c9e7a5bSclaudio sizeof(struct iface)) 288a1a4e97bSnorby fatalx("IFINFO imsg with wrong len"); 2896c9e7a5bSclaudio ifp = imsg.data; 290a1a4e97bSnorby 291a66c91f2Sremi LIST_FOREACH(area, &oeconf->area_list, entry) { 292a66c91f2Sremi LIST_FOREACH(i, &area->iface_list, entry) { 293a66c91f2Sremi if (strcmp(i->dependon, 294a66c91f2Sremi ifp->name) == 0) { 295a66c91f2Sremi log_warnx("interface %s" 296a66c91f2Sremi " changed state, %s" 297a66c91f2Sremi " depends on it", 298a66c91f2Sremi ifp->name, i->name); 299a66c91f2Sremi i->depend_ok = 300a66c91f2Sremi ifstate_is_up(ifp); 301a66c91f2Sremi if (ifstate_is_up(i)) 302d18517d2Sdenis orig_rtr_lsa(i->area); 303a66c91f2Sremi } 304a66c91f2Sremi } 305a66c91f2Sremi } 306a66c91f2Sremi 307a66c91f2Sremi if (!(ifp->cflags & F_IFACE_CONFIGURED)) 308a66c91f2Sremi break; 3096c9e7a5bSclaudio iface = if_find(ifp->ifindex); 3106c9e7a5bSclaudio if (iface == NULL) 3116c9e7a5bSclaudio fatalx("interface lost in ospfe"); 31242176c47Sclaudio 3130dcde55eSjca wasvalid = (iface->flags & IFF_UP) && 3140dcde55eSjca LINK_STATE_IS_UP(iface->linkstate); 3150dcde55eSjca 31618ffdd94Sstsp if_update(iface, ifp->mtu, ifp->flags, ifp->if_type, 3175d393f89Sremi ifp->linkstate, ifp->baudrate, ifp->rdomain); 318a1a4e97bSnorby 3190dcde55eSjca isvalid = (iface->flags & IFF_UP) && 3200dcde55eSjca LINK_STATE_IS_UP(iface->linkstate); 3210dcde55eSjca 3220dcde55eSjca if (wasvalid == isvalid) 3230dcde55eSjca break; 3240dcde55eSjca 3250dcde55eSjca if (isvalid) { 3266c9e7a5bSclaudio if_fsm(iface, IF_EVT_UP); 3276c9e7a5bSclaudio log_warnx("interface %s up", iface->name); 328a1a4e97bSnorby } else { 3296c9e7a5bSclaudio if_fsm(iface, IF_EVT_DOWN); 3306c9e7a5bSclaudio log_warnx("interface %s down", iface->name); 331a1a4e97bSnorby } 3326c9e7a5bSclaudio break; 3338e1674f3Sbluhm case IMSG_IFADDRNEW: 3348e1674f3Sbluhm if (imsg.hdr.len != IMSG_HEADER_SIZE + 3358e1674f3Sbluhm sizeof(struct ifaddrchange)) 3368e1674f3Sbluhm fatalx("IFADDRNEW imsg with wrong len"); 3378e1674f3Sbluhm ifc = imsg.data; 3388e1674f3Sbluhm 3398e1674f3Sbluhm iface = if_find(ifc->ifindex); 3408e1674f3Sbluhm if (iface == NULL) 3418e1674f3Sbluhm fatalx("IFADDRNEW interface lost in ospfe"); 3428e1674f3Sbluhm 3438e1674f3Sbluhm if ((ia = calloc(1, sizeof(struct iface_addr))) == 3448e1674f3Sbluhm NULL) 3458e1674f3Sbluhm fatal("ospfe_dispatch_main IFADDRNEW"); 3468e1674f3Sbluhm ia->addr = ifc->addr; 3478e1674f3Sbluhm ia->dstbrd = ifc->dstbrd; 3488e1674f3Sbluhm ia->prefixlen = ifc->prefixlen; 3498e1674f3Sbluhm 3508e1674f3Sbluhm TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry); 3518e1674f3Sbluhm orig_link_lsa(iface); 3528e1674f3Sbluhm break; 3538e1674f3Sbluhm case IMSG_IFADDRDEL: 3548e1674f3Sbluhm if (imsg.hdr.len != IMSG_HEADER_SIZE + 3558e1674f3Sbluhm sizeof(struct ifaddrchange)) 3568e1674f3Sbluhm fatalx("IFADDRDEL imsg with wrong len"); 3578e1674f3Sbluhm ifc = imsg.data; 3588e1674f3Sbluhm 3598e1674f3Sbluhm iface = if_find(ifc->ifindex); 3608e1674f3Sbluhm if (iface == NULL) 3618e1674f3Sbluhm fatalx("IFADDRDEL interface lost in ospfe"); 3628e1674f3Sbluhm 3638e1674f3Sbluhm for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL; 3648e1674f3Sbluhm ia = nia) { 3658e1674f3Sbluhm nia = TAILQ_NEXT(ia, entry); 3668e1674f3Sbluhm 3678e1674f3Sbluhm if (IN6_ARE_ADDR_EQUAL(&ia->addr, 3688e1674f3Sbluhm &ifc->addr)) { 3698e1674f3Sbluhm TAILQ_REMOVE(&iface->ifa_list, ia, 3708e1674f3Sbluhm entry); 3718e1674f3Sbluhm free(ia); 3728e1674f3Sbluhm break; 3738e1674f3Sbluhm } 3748e1674f3Sbluhm } 3758e1674f3Sbluhm orig_link_lsa(iface); 3768e1674f3Sbluhm break; 377a1a4e97bSnorby case IMSG_RECONF_CONF: 37877138d9fSclaudio if ((noeconf = malloc(sizeof(struct ospfd_conf))) == 379a1a4e97bSnorby NULL) 380a1a4e97bSnorby fatal(NULL); 38177138d9fSclaudio memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf)); 382a1a4e97bSnorby 38377138d9fSclaudio LIST_INIT(&noeconf->area_list); 38477138d9fSclaudio LIST_INIT(&noeconf->cand_list); 385a1a4e97bSnorby break; 386a1a4e97bSnorby case IMSG_RECONF_AREA: 387a1a4e97bSnorby if ((narea = area_new()) == NULL) 388a1a4e97bSnorby fatal(NULL); 389a1a4e97bSnorby memcpy(narea, imsg.data, sizeof(struct area)); 390a1a4e97bSnorby 391a1a4e97bSnorby LIST_INIT(&narea->iface_list); 392a1a4e97bSnorby LIST_INIT(&narea->nbr_list); 393a1a4e97bSnorby RB_INIT(&narea->lsa_tree); 394a1a4e97bSnorby 39577138d9fSclaudio LIST_INSERT_HEAD(&noeconf->area_list, narea, entry); 396a1a4e97bSnorby break; 397a1a4e97bSnorby case IMSG_RECONF_END: 398a1a4e97bSnorby if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) != 39977138d9fSclaudio (noeconf->flags & OSPFD_FLAG_STUB_ROUTER)) 400a1a4e97bSnorby stub_changed = 1; 401a1a4e97bSnorby else 402a1a4e97bSnorby stub_changed = 0; 40377138d9fSclaudio merge_config(oeconf, noeconf); 40477138d9fSclaudio noeconf = NULL; 405a1a4e97bSnorby if (stub_changed) 406a1a4e97bSnorby orig_rtr_lsa_all(NULL); 407a1a4e97bSnorby break; 408a1a4e97bSnorby case IMSG_CTL_KROUTE: 409a1a4e97bSnorby case IMSG_CTL_KROUTE_ADDR: 410a1a4e97bSnorby case IMSG_CTL_END: 411a1a4e97bSnorby control_imsg_relay(&imsg); 412a1a4e97bSnorby break; 413cb75d791Sremi case IMSG_CONTROLFD: 4145608ad94Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 415cb75d791Sremi fatalx("%s: expected to receive imsg control" 416cb75d791Sremi "fd but didn't receive any", __func__); 417cb75d791Sremi /* Listen on control socket. */ 418bf1e0606Sclaudio control_listen(fd); 419cb75d791Sremi if (pledge("stdio inet mcast", NULL) == -1) 420cb75d791Sremi fatal("pledge"); 421cb75d791Sremi break; 422a1a4e97bSnorby default: 423a1a4e97bSnorby log_debug("ospfe_dispatch_main: error handling imsg %d", 424a1a4e97bSnorby imsg.hdr.type); 425a1a4e97bSnorby break; 426a1a4e97bSnorby } 427a1a4e97bSnorby imsg_free(&imsg); 428a1a4e97bSnorby } 429a1a4e97bSnorby if (!shut) 430f78850efSeric imsg_event_add(iev); 431a1a4e97bSnorby else { 432a1a4e97bSnorby /* this pipe is dead, so remove the event handler */ 433f78850efSeric event_del(&iev->ev); 434a1a4e97bSnorby event_loopexit(NULL); 435a1a4e97bSnorby } 436a1a4e97bSnorby } 437a1a4e97bSnorby 438a1a4e97bSnorby void 439a1a4e97bSnorby ospfe_dispatch_rde(int fd, short event, void *bula) 440a1a4e97bSnorby { 441a1a4e97bSnorby struct lsa_hdr lsa_hdr; 4423608871eSbluhm struct lsa_link lsa_link; 443f78850efSeric struct imsgev *iev = bula; 444f78850efSeric struct imsgbuf *ibuf = &iev->ibuf; 445a1a4e97bSnorby struct nbr *nbr; 446a1a4e97bSnorby struct lsa_hdr *lhp; 447a1a4e97bSnorby struct lsa_ref *ref; 448a1a4e97bSnorby struct area *area; 449a1a4e97bSnorby struct iface *iface; 450a1a4e97bSnorby struct lsa_entry *le; 451a1a4e97bSnorby struct imsg imsg; 452a1a4e97bSnorby struct abr_rtr ar; 453a1a4e97bSnorby int n, noack = 0, shut = 0; 454a1a4e97bSnorby u_int16_t l, age; 455a1a4e97bSnorby 45641e7b05eSclaudio if (event & EV_READ) { 457668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 458dd7efffeSclaudio fatal("imsgbuf_read error"); 459a1a4e97bSnorby if (n == 0) /* connection closed */ 460a1a4e97bSnorby shut = 1; 46141e7b05eSclaudio } 46241e7b05eSclaudio if (event & EV_WRITE) { 463dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 464c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 4651203692fSkrw shut = 1; 466c1aa9554Sclaudio else 467dd7efffeSclaudio fatal("imsgbuf_write"); 468c1aa9554Sclaudio } 469a1a4e97bSnorby } 470a1a4e97bSnorby 471a1a4e97bSnorby for (;;) { 472a1a4e97bSnorby if ((n = imsg_get(ibuf, &imsg)) == -1) 473262992b2Sclaudio fatal("ospfe_dispatch_rde: imsg_get error"); 474a1a4e97bSnorby if (n == 0) 475a1a4e97bSnorby break; 476a1a4e97bSnorby 477a1a4e97bSnorby switch (imsg.hdr.type) { 478a1a4e97bSnorby case IMSG_DD: 479a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 480a1a4e97bSnorby if (nbr == NULL) 481a1a4e97bSnorby break; 482a1a4e97bSnorby 483a1a4e97bSnorby /* put these on my ls_req_list for retrieval */ 484a1a4e97bSnorby lhp = lsa_hdr_new(); 485a1a4e97bSnorby memcpy(lhp, imsg.data, sizeof(*lhp)); 486a1a4e97bSnorby ls_req_list_add(nbr, lhp); 487a1a4e97bSnorby break; 488a1a4e97bSnorby case IMSG_DD_END: 489a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 490a1a4e97bSnorby if (nbr == NULL) 491a1a4e97bSnorby break; 492a1a4e97bSnorby 493a1a4e97bSnorby nbr->dd_pending--; 494a1a4e97bSnorby if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) { 495a1a4e97bSnorby if (ls_req_list_empty(nbr)) 496a1a4e97bSnorby nbr_fsm(nbr, NBR_EVT_LOAD_DONE); 497a1a4e97bSnorby else 498a1a4e97bSnorby start_ls_req_tx_timer(nbr); 499a1a4e97bSnorby } 500a1a4e97bSnorby break; 501a1a4e97bSnorby case IMSG_DB_SNAPSHOT: 502a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 503a1a4e97bSnorby if (nbr == NULL) 504a1a4e97bSnorby break; 50525bf10dbSmarkus if (nbr->state != NBR_STA_SNAP) /* discard */ 50625bf10dbSmarkus break; 507a1a4e97bSnorby 508a1a4e97bSnorby /* add LSA header to the neighbor db_sum_list */ 509a1a4e97bSnorby lhp = lsa_hdr_new(); 510a1a4e97bSnorby memcpy(lhp, imsg.data, sizeof(*lhp)); 511a1a4e97bSnorby db_sum_list_add(nbr, lhp); 512a1a4e97bSnorby break; 513a1a4e97bSnorby case IMSG_DB_END: 514a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 515a1a4e97bSnorby if (nbr == NULL) 516a1a4e97bSnorby break; 517a1a4e97bSnorby 51825bf10dbSmarkus nbr->dd_snapshot = 0; 51925bf10dbSmarkus if (nbr->state != NBR_STA_SNAP) 52025bf10dbSmarkus break; 52125bf10dbSmarkus 522a1a4e97bSnorby /* snapshot done, start tx of dd packets */ 523a1a4e97bSnorby nbr_fsm(nbr, NBR_EVT_SNAP_DONE); 524a1a4e97bSnorby break; 525a1a4e97bSnorby case IMSG_LS_FLOOD: 526a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 527a1a4e97bSnorby if (nbr == NULL) 528a1a4e97bSnorby break; 529a1a4e97bSnorby 530a1a4e97bSnorby l = imsg.hdr.len - IMSG_HEADER_SIZE; 531a1a4e97bSnorby if (l < sizeof(lsa_hdr)) 532a1a4e97bSnorby fatalx("ospfe_dispatch_rde: " 533a1a4e97bSnorby "bad imsg size"); 534a1a4e97bSnorby memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 535a1a4e97bSnorby 536a1a4e97bSnorby ref = lsa_cache_add(imsg.data, l); 537a1a4e97bSnorby 538d913b22eSclaudio if (lsa_hdr.type == htons(LSA_TYPE_EXTERNAL)) { 539a1a4e97bSnorby /* 540a1a4e97bSnorby * flood on all areas but stub areas and 541a1a4e97bSnorby * virtual links 542a1a4e97bSnorby */ 543a1a4e97bSnorby LIST_FOREACH(area, &oeconf->area_list, entry) { 544a1a4e97bSnorby if (area->stub) 545a1a4e97bSnorby continue; 546a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, 547a1a4e97bSnorby entry) { 548a1a4e97bSnorby noack += lsa_flood(iface, nbr, 549a1a4e97bSnorby &lsa_hdr, imsg.data); 550a1a4e97bSnorby } 551a1a4e97bSnorby } 552d913b22eSclaudio } else if (lsa_hdr.type == htons(LSA_TYPE_LINK)) { 553d913b22eSclaudio /* 5543608871eSbluhm * Save link-LSA options of neighbor. 5553608871eSbluhm * This is needed to originate network-LSA. 5563608871eSbluhm */ 5573608871eSbluhm if (l - sizeof(lsa_hdr) < sizeof(lsa_link)) 5583608871eSbluhm fatalx("ospfe_dispatch_rde: " 5593608871eSbluhm "bad imsg link size"); 5603608871eSbluhm memcpy(&lsa_link, (char *)imsg.data + 5613608871eSbluhm sizeof(lsa_hdr), sizeof(lsa_link)); 5623608871eSbluhm nbr->link_options = lsa_link.opts & 5633608871eSbluhm htonl(LSA_24_MASK); 5643608871eSbluhm 5653608871eSbluhm /* 566d913b22eSclaudio * flood on interface only 567d913b22eSclaudio */ 568d913b22eSclaudio noack += lsa_flood(nbr->iface, nbr, 569d913b22eSclaudio &lsa_hdr, imsg.data); 570a1a4e97bSnorby } else { 571a1a4e97bSnorby /* 572a1a4e97bSnorby * flood on all area interfaces on 573a1a4e97bSnorby * area 0.0.0.0 include also virtual links. 574a1a4e97bSnorby */ 57577fbfa19Sdenis LIST_FOREACH(iface, 57677fbfa19Sdenis &nbr->iface->area->iface_list, entry) { 577a1a4e97bSnorby noack += lsa_flood(iface, nbr, 578a1a4e97bSnorby &lsa_hdr, imsg.data); 579a1a4e97bSnorby } 580a1a4e97bSnorby /* XXX virtual links */ 581a1a4e97bSnorby } 582a1a4e97bSnorby 583a1a4e97bSnorby /* remove from ls_req_list */ 584a1a4e97bSnorby le = ls_req_list_get(nbr, &lsa_hdr); 585a1a4e97bSnorby if (!(nbr->state & NBR_STA_FULL) && le != NULL) { 586a1a4e97bSnorby ls_req_list_free(nbr, le); 587a1a4e97bSnorby /* 588a1a4e97bSnorby * XXX no need to ack requested lsa 589a1a4e97bSnorby * the problem is that the RFC is very 590a1a4e97bSnorby * unclear about this. 591a1a4e97bSnorby */ 592a1a4e97bSnorby noack = 1; 593a1a4e97bSnorby } 594a1a4e97bSnorby 595a1a4e97bSnorby if (!noack && nbr->iface != NULL && 596a1a4e97bSnorby nbr->iface->self != nbr) { 597a1a4e97bSnorby if (!(nbr->iface->state & IF_STA_BACKUP) || 598a1a4e97bSnorby nbr->iface->dr == nbr) { 599a1a4e97bSnorby /* delayed ack */ 600a1a4e97bSnorby lhp = lsa_hdr_new(); 601a1a4e97bSnorby memcpy(lhp, &lsa_hdr, sizeof(*lhp)); 602a1a4e97bSnorby ls_ack_list_add(nbr->iface, lhp); 603a1a4e97bSnorby } 604a1a4e97bSnorby } 605a1a4e97bSnorby 606a1a4e97bSnorby lsa_cache_put(ref, nbr); 607a1a4e97bSnorby break; 608a1a4e97bSnorby case IMSG_LS_UPD: 60925bf10dbSmarkus case IMSG_LS_SNAP: 610a1a4e97bSnorby /* 61125bf10dbSmarkus * IMSG_LS_UPD is used in two cases: 612a1a4e97bSnorby * 1. as response to ls requests 613a1a4e97bSnorby * 2. as response to ls updates where the DB 614a1a4e97bSnorby * is newer then the sent LSA 61525bf10dbSmarkus * IMSG_LS_SNAP is used in one case: 61625bf10dbSmarkus * in EXSTART when the LSA has age MaxAge 617a1a4e97bSnorby */ 618a1a4e97bSnorby l = imsg.hdr.len - IMSG_HEADER_SIZE; 619a1a4e97bSnorby if (l < sizeof(lsa_hdr)) 620a1a4e97bSnorby fatalx("ospfe_dispatch_rde: " 621a1a4e97bSnorby "bad imsg size"); 622a1a4e97bSnorby 623a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 624a1a4e97bSnorby if (nbr == NULL) 625a1a4e97bSnorby break; 626a1a4e97bSnorby 627a1a4e97bSnorby if (nbr->iface->self == nbr) 628a1a4e97bSnorby break; 629a1a4e97bSnorby 63025bf10dbSmarkus if (imsg.hdr.type == IMSG_LS_SNAP && 63125bf10dbSmarkus nbr->state != NBR_STA_SNAP) 63225bf10dbSmarkus break; 63325bf10dbSmarkus 634a1a4e97bSnorby memcpy(&age, imsg.data, sizeof(age)); 635a1a4e97bSnorby ref = lsa_cache_add(imsg.data, l); 636a1a4e97bSnorby if (ntohs(age) >= MAX_AGE) 637a1a4e97bSnorby /* add to retransmit list */ 638a1a4e97bSnorby ls_retrans_list_add(nbr, imsg.data, 0, 0); 639a1a4e97bSnorby else 640a1a4e97bSnorby ls_retrans_list_add(nbr, imsg.data, 0, 1); 641a1a4e97bSnorby 642a1a4e97bSnorby lsa_cache_put(ref, nbr); 643a1a4e97bSnorby break; 644a1a4e97bSnorby case IMSG_LS_ACK: 645a1a4e97bSnorby /* 646a1a4e97bSnorby * IMSG_LS_ACK is used in two cases: 647a1a4e97bSnorby * 1. LSA was a duplicate 648a1a4e97bSnorby * 2. LS age is MaxAge and there is no current 649a1a4e97bSnorby * instance in the DB plus no neighbor in state 650a1a4e97bSnorby * Exchange or Loading 651a1a4e97bSnorby */ 652a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 653a1a4e97bSnorby if (nbr == NULL) 654a1a4e97bSnorby break; 655a1a4e97bSnorby 656a1a4e97bSnorby if (nbr->iface->self == nbr) 657a1a4e97bSnorby break; 658a1a4e97bSnorby 659a1a4e97bSnorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr)) 660a1a4e97bSnorby fatalx("ospfe_dispatch_rde: bad imsg size"); 661a1a4e97bSnorby memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 662a1a4e97bSnorby 663a1a4e97bSnorby /* for case one check for implied acks */ 664a1a4e97bSnorby if (nbr->iface->state & IF_STA_DROTHER) 665a1a4e97bSnorby if (ls_retrans_list_del(nbr->iface->self, 666a1a4e97bSnorby &lsa_hdr) == 0) 667a1a4e97bSnorby break; 668a1a4e97bSnorby if (ls_retrans_list_del(nbr, &lsa_hdr) == 0) 669a1a4e97bSnorby break; 670a1a4e97bSnorby 671a1a4e97bSnorby /* send a direct acknowledgement */ 6720a137951Sdenis send_direct_ack(nbr->iface, nbr->addr, imsg.data, 673a1a4e97bSnorby imsg.hdr.len - IMSG_HEADER_SIZE); 674a1a4e97bSnorby 675a1a4e97bSnorby break; 676a1a4e97bSnorby case IMSG_LS_BADREQ: 677a1a4e97bSnorby nbr = nbr_find_peerid(imsg.hdr.peerid); 678a1a4e97bSnorby if (nbr == NULL) 679a1a4e97bSnorby break; 680a1a4e97bSnorby 681a1a4e97bSnorby if (nbr->iface->self == nbr) 682a1a4e97bSnorby fatalx("ospfe_dispatch_rde: " 683a1a4e97bSnorby "dummy neighbor got BADREQ"); 684a1a4e97bSnorby 685a1a4e97bSnorby nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ); 686a1a4e97bSnorby break; 687a1a4e97bSnorby case IMSG_ABR_UP: 688a1a4e97bSnorby memcpy(&ar, imsg.data, sizeof(ar)); 689a1a4e97bSnorby 690a1a4e97bSnorby if ((iface = find_vlink(&ar)) != NULL && 691a1a4e97bSnorby iface->state == IF_STA_DOWN) 692a1a4e97bSnorby if (if_fsm(iface, IF_EVT_UP)) { 693a1a4e97bSnorby log_debug("error starting interface %s", 694a1a4e97bSnorby iface->name); 695a1a4e97bSnorby } 696a1a4e97bSnorby break; 697a1a4e97bSnorby case IMSG_ABR_DOWN: 698a1a4e97bSnorby memcpy(&ar, imsg.data, sizeof(ar)); 699a1a4e97bSnorby 700a1a4e97bSnorby if ((iface = find_vlink(&ar)) != NULL && 701a1a4e97bSnorby iface->state == IF_STA_POINTTOPOINT) 702a1a4e97bSnorby if (if_fsm(iface, IF_EVT_DOWN)) { 703a1a4e97bSnorby log_debug("error stopping interface %s", 704a1a4e97bSnorby iface->name); 705a1a4e97bSnorby } 706a1a4e97bSnorby break; 707a1a4e97bSnorby case IMSG_CTL_AREA: 7084ae44e47Sclaudio case IMSG_CTL_IFACE: 709a1a4e97bSnorby case IMSG_CTL_END: 710a1a4e97bSnorby case IMSG_CTL_SHOW_DATABASE: 711a1a4e97bSnorby case IMSG_CTL_SHOW_DB_EXT: 712d913b22eSclaudio case IMSG_CTL_SHOW_DB_LINK: 713a1a4e97bSnorby case IMSG_CTL_SHOW_DB_NET: 714a1a4e97bSnorby case IMSG_CTL_SHOW_DB_RTR: 715d5dafa54Sstsp case IMSG_CTL_SHOW_DB_INTRA: 716a1a4e97bSnorby case IMSG_CTL_SHOW_DB_SELF: 717a1a4e97bSnorby case IMSG_CTL_SHOW_DB_SUM: 718a1a4e97bSnorby case IMSG_CTL_SHOW_DB_ASBR: 719a1a4e97bSnorby case IMSG_CTL_SHOW_RIB: 720a1a4e97bSnorby case IMSG_CTL_SHOW_SUM: 721a1a4e97bSnorby case IMSG_CTL_SHOW_SUM_AREA: 722a1a4e97bSnorby control_imsg_relay(&imsg); 723a1a4e97bSnorby break; 724a1a4e97bSnorby default: 725a1a4e97bSnorby log_debug("ospfe_dispatch_rde: error handling imsg %d", 726a1a4e97bSnorby imsg.hdr.type); 727a1a4e97bSnorby break; 728a1a4e97bSnorby } 729a1a4e97bSnorby imsg_free(&imsg); 730a1a4e97bSnorby } 731a1a4e97bSnorby if (!shut) 732f78850efSeric imsg_event_add(iev); 733a1a4e97bSnorby else { 734a1a4e97bSnorby /* this pipe is dead, so remove the event handler */ 735f78850efSeric event_del(&iev->ev); 736a1a4e97bSnorby event_loopexit(NULL); 737a1a4e97bSnorby } 738a1a4e97bSnorby } 739a1a4e97bSnorby 740a1a4e97bSnorby struct iface * 741a1a4e97bSnorby find_vlink(struct abr_rtr *ar) 742a1a4e97bSnorby { 743a1a4e97bSnorby struct area *area; 744a1a4e97bSnorby struct iface *iface = NULL; 745a1a4e97bSnorby 746a1a4e97bSnorby LIST_FOREACH(area, &oeconf->area_list, entry) 747a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, entry) 748a1a4e97bSnorby if (iface->abr_id.s_addr == ar->abr_id.s_addr && 749a1a4e97bSnorby iface->type == IF_TYPE_VIRTUALLINK && 75077fbfa19Sdenis iface->area->id.s_addr == ar->area.s_addr) { 751a1a4e97bSnorby iface->dst = ar->dst_ip; 752a1a4e97bSnorby iface->addr = ar->addr; 753a1a4e97bSnorby iface->metric = ar->metric; 754a1a4e97bSnorby 755a1a4e97bSnorby return (iface); 756a1a4e97bSnorby } 757a1a4e97bSnorby 758a1a4e97bSnorby return (iface); 759a1a4e97bSnorby } 760a1a4e97bSnorby 761a1a4e97bSnorby void 762a1a4e97bSnorby orig_rtr_lsa_all(struct area *area) 763a1a4e97bSnorby { 764a1a4e97bSnorby struct area *a; 765a1a4e97bSnorby 766a1a4e97bSnorby /* 767a1a4e97bSnorby * update all router LSA in all areas except area itself, 768a1a4e97bSnorby * as this update is already running. 769a1a4e97bSnorby */ 770a1a4e97bSnorby LIST_FOREACH(a, &oeconf->area_list, entry) 771a1a4e97bSnorby if (a != area) 772d18517d2Sdenis orig_rtr_lsa(a); 773a1a4e97bSnorby } 774a1a4e97bSnorby 775a1a4e97bSnorby void 776d18517d2Sdenis orig_rtr_lsa(struct area *area) 777a1a4e97bSnorby { 778a1a4e97bSnorby struct lsa_hdr lsa_hdr; 779a1a4e97bSnorby struct lsa_rtr lsa_rtr; 780a1a4e97bSnorby struct lsa_rtr_link rtr_link; 781a1a4e97bSnorby struct iface *iface; 782e39620e5Snicm struct ibuf *buf; 783a1a4e97bSnorby struct nbr *nbr, *self = NULL; 7848c389b43Sclaudio u_int32_t flags; 785a1a4e97bSnorby u_int16_t chksum; 786a1a4e97bSnorby u_int8_t border, virtual = 0; 787a1a4e97bSnorby 788a1a4e97bSnorby log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id)); 789a1a4e97bSnorby 790e39620e5Snicm /* XXX IBUF_READ_SIZE */ 791e39620e5Snicm if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL) 792a1a4e97bSnorby fatal("orig_rtr_lsa"); 793a1a4e97bSnorby 794a1a4e97bSnorby /* reserve space for LSA header and LSA Router header */ 795297c3ba2Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_hdr)) == -1) 796297c3ba2Sclaudio fatal("orig_rtr_lsa: ibuf_add_zero failed"); 797a1a4e97bSnorby 798297c3ba2Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_rtr)) == -1) 799297c3ba2Sclaudio fatal("orig_rtr_lsa: ibuf_add_zero failed"); 800a1a4e97bSnorby 801a1a4e97bSnorby /* links */ 802a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, entry) { 803a1a4e97bSnorby if (self == NULL && iface->self != NULL) 804a1a4e97bSnorby self = iface->self; 805a1a4e97bSnorby 806a1a4e97bSnorby bzero(&rtr_link, sizeof(rtr_link)); 807a1a4e97bSnorby 808a1a4e97bSnorby switch (iface->type) { 809a1a4e97bSnorby case IF_TYPE_POINTOPOINT: 810a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) 811a1a4e97bSnorby if (nbr != iface->self && 812a1a4e97bSnorby nbr->state & NBR_STA_FULL) 813a1a4e97bSnorby break; 814273e69bcSstsp if (nbr && iface->state & IF_STA_POINTTOPOINT) { 815a1a4e97bSnorby log_debug("orig_rtr_lsa: point-to-point, " 816a1a4e97bSnorby "interface %s", iface->name); 817a1a4e97bSnorby rtr_link.type = LINK_TYPE_POINTTOPOINT; 818a66c91f2Sremi if (iface->dependon[0] != '\0' && 819a66c91f2Sremi iface->depend_ok == 0) 820a66c91f2Sremi rtr_link.metric = MAX_METRIC; 821a66c91f2Sremi else 822a1a4e97bSnorby rtr_link.metric = htons(iface->metric); 823273e69bcSstsp rtr_link.iface_id = htonl(iface->ifindex); 824273e69bcSstsp rtr_link.nbr_iface_id = htonl(nbr->iface_id); 825273e69bcSstsp rtr_link.nbr_rtr_id = nbr->id.s_addr; 826e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 8272c6b772cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 828a1a4e97bSnorby } 829a1a4e97bSnorby continue; 830a1a4e97bSnorby case IF_TYPE_BROADCAST: 831a1a4e97bSnorby case IF_TYPE_NBMA: 832a1a4e97bSnorby if ((iface->state & IF_STA_MULTI)) { 833a1a4e97bSnorby if (iface->dr == iface->self) { 834a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, 835a1a4e97bSnorby entry) 836a1a4e97bSnorby if (nbr != iface->self && 837a1a4e97bSnorby nbr->state & NBR_STA_FULL) 838a1a4e97bSnorby break; 839a1a4e97bSnorby } else 840a1a4e97bSnorby nbr = iface->dr; 841a1a4e97bSnorby 842a1a4e97bSnorby if (nbr && nbr->state & NBR_STA_FULL) { 843a1a4e97bSnorby log_debug("orig_rtr_lsa: transit net, " 844a1a4e97bSnorby "interface %s", iface->name); 845a1a4e97bSnorby 846a1a4e97bSnorby rtr_link.type = LINK_TYPE_TRANSIT_NET; 847a66c91f2Sremi if (iface->dependon[0] != '\0' && 848a66c91f2Sremi iface->depend_ok == 0) 849a66c91f2Sremi rtr_link.metric = MAX_METRIC; 850a66c91f2Sremi else 851a66c91f2Sremi rtr_link.metric = 852a66c91f2Sremi htons(iface->metric); 8538c389b43Sclaudio rtr_link.iface_id = htonl(iface->ifindex); 8548c389b43Sclaudio rtr_link.nbr_iface_id = htonl(iface->dr->iface_id); 8558c389b43Sclaudio rtr_link.nbr_rtr_id = iface->dr->id.s_addr; 856e39620e5Snicm if (ibuf_add(buf, &rtr_link, 8578c389b43Sclaudio sizeof(rtr_link))) 8588c389b43Sclaudio fatalx("orig_rtr_lsa: " 8592c6b772cSclaudio "ibuf_add failed"); 860a1a4e97bSnorby break; 861a1a4e97bSnorby } 862a1a4e97bSnorby } 863a1a4e97bSnorby break; 8648c389b43Sclaudio #if 0 /* TODO virtualllink/pointtomulti */ 865a1a4e97bSnorby case IF_TYPE_VIRTUALLINK: 866a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) { 867a1a4e97bSnorby if (nbr != iface->self && 868a1a4e97bSnorby nbr->state & NBR_STA_FULL) 869a1a4e97bSnorby break; 870a1a4e97bSnorby } 871a1a4e97bSnorby if (nbr) { 872a1a4e97bSnorby rtr_link.id = nbr->id.s_addr; 873a1a4e97bSnorby //XXX rtr_link.data = iface->addr.s_addr; 874a1a4e97bSnorby rtr_link.type = LINK_TYPE_VIRTUAL; 875a1a4e97bSnorby /* RFC 3137: stub router support */ 876a1a4e97bSnorby if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER || 877a1a4e97bSnorby oe_nofib) 878a1a4e97bSnorby rtr_link.metric = 0xffff; 879a1a4e97bSnorby else 880a1a4e97bSnorby rtr_link.metric = htons(iface->metric); 881a1a4e97bSnorby virtual = 1; 882e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 8832c6b772cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 884a1a4e97bSnorby 885a1a4e97bSnorby log_debug("orig_rtr_lsa: virtual link, " 886a1a4e97bSnorby "interface %s", iface->name); 887a1a4e97bSnorby } 888a1a4e97bSnorby continue; 889a1a4e97bSnorby case IF_TYPE_POINTOMULTIPOINT: 890a1a4e97bSnorby log_debug("orig_rtr_lsa: stub net, " 891a1a4e97bSnorby "interface %s", iface->name); 892a1a4e97bSnorby //XXX rtr_link.id = iface->addr.s_addr; 893a1a4e97bSnorby rtr_link.data = 0xffffffff; 894a1a4e97bSnorby rtr_link.type = LINK_TYPE_STUB_NET; 895a1a4e97bSnorby rtr_link.metric = htons(iface->metric); 896e39620e5Snicm if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 8972c6b772cSclaudio fatalx("orig_rtr_lsa: ibuf_add failed"); 898a1a4e97bSnorby 899a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) { 900a1a4e97bSnorby if (nbr != iface->self && 901a1a4e97bSnorby nbr->state & NBR_STA_FULL) { 902a1a4e97bSnorby bzero(&rtr_link, sizeof(rtr_link)); 903a1a4e97bSnorby log_debug("orig_rtr_lsa: " 904a1a4e97bSnorby "point-to-multipoint, interface %s", 905a1a4e97bSnorby iface->name); 906a1a4e97bSnorby //XXX rtr_link.id = nbr->addr.s_addr; 907a1a4e97bSnorby //XXX rtr_link.data = iface->addr.s_addr; 908a1a4e97bSnorby rtr_link.type = LINK_TYPE_POINTTOPOINT; 909a1a4e97bSnorby /* RFC 3137: stub router support */ 910a1a4e97bSnorby if (oe_nofib || oeconf->flags & 911a1a4e97bSnorby OSPFD_FLAG_STUB_ROUTER) 912a66c91f2Sremi rtr_link.metric = MAX_METRIC; 913a66c91f2Sremi else if (iface->dependon[0] != '\0' && 914a66c91f2Sremi iface->dependon_ok == 0) 915a66c91f2Sremi rtr_link.metric = MAX_METRIC; 916a1a4e97bSnorby else 917a1a4e97bSnorby rtr_link.metric = 918a1a4e97bSnorby htons(iface->metric); 919e39620e5Snicm if (ibuf_add(buf, &rtr_link, 920a1a4e97bSnorby sizeof(rtr_link))) 921a1a4e97bSnorby fatalx("orig_rtr_lsa: " 9222c6b772cSclaudio "ibuf_add failed"); 923a1a4e97bSnorby } 924a1a4e97bSnorby } 925a1a4e97bSnorby continue; 9268c389b43Sclaudio #endif /* TODO virtualllink/pointtomulti */ 927a1a4e97bSnorby default: 928a1a4e97bSnorby fatalx("orig_rtr_lsa: unknown interface type"); 929a1a4e97bSnorby } 930a1a4e97bSnorby } 931a1a4e97bSnorby 932a1a4e97bSnorby /* LSA router header */ 9338c389b43Sclaudio lsa_rtr.opts = 0; 9348c389b43Sclaudio flags = 0; 9358c389b43Sclaudio 936a1a4e97bSnorby /* 937a1a4e97bSnorby * Set the E bit as soon as an as-ext lsa may be redistributed, only 938a1a4e97bSnorby * setting it in case we redistribute something is not worth the fuss. 939a1a4e97bSnorby */ 940c2625c19Sclaudio if (oeconf->redistribute && !area->stub) 9418c389b43Sclaudio flags |= OSPF_RTR_E; 942a1a4e97bSnorby 943a1a4e97bSnorby border = (area_border_router(oeconf) != 0); 944a1a4e97bSnorby if (border != oeconf->border) { 945a1a4e97bSnorby oeconf->border = border; 946a1a4e97bSnorby orig_rtr_lsa_all(area); 947a1a4e97bSnorby } 948a1a4e97bSnorby 949a1a4e97bSnorby if (oeconf->border) 9508c389b43Sclaudio flags |= OSPF_RTR_B; 951a1a4e97bSnorby /* TODO set V flag if a active virtual link ends here and the 9525934d87dSsthen * area is the transit area for this link. */ 953a1a4e97bSnorby if (virtual) 9548c389b43Sclaudio flags |= OSPF_RTR_V; 955a1a4e97bSnorby 9568c389b43Sclaudio LSA_24_SETLO(lsa_rtr.opts, area_ospf_options(area)); 9578c389b43Sclaudio LSA_24_SETHI(lsa_rtr.opts, flags); 9582773be1bSclaudio lsa_rtr.opts = htonl(lsa_rtr.opts); 959297c3ba2Sclaudio if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_rtr, sizeof(lsa_rtr)) == -1) 960297c3ba2Sclaudio fatal("orig_rtr_lsa: ibuf_set failed"); 961a1a4e97bSnorby 962a1a4e97bSnorby /* LSA header */ 963a1a4e97bSnorby lsa_hdr.age = htons(DEFAULT_AGE); 9648c389b43Sclaudio lsa_hdr.type = htons(LSA_TYPE_ROUTER); 9658c389b43Sclaudio /* XXX needs to be fixed if multiple router-lsa need to be announced */ 9668c389b43Sclaudio lsa_hdr.ls_id = 0; 967a1a4e97bSnorby lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 968a1a4e97bSnorby lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 969bf2cf305Sclaudio lsa_hdr.len = htons(ibuf_size(buf)); 970a1a4e97bSnorby lsa_hdr.ls_chksum = 0; /* updated later */ 971297c3ba2Sclaudio if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1) 972297c3ba2Sclaudio fatal("orig_rtr_lsa: ibuf_set failed"); 973a1a4e97bSnorby 974bf2cf305Sclaudio chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET); 975297c3ba2Sclaudio if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1) 976297c3ba2Sclaudio fatal("orig_rtr_lsa: ibuf_set_n16 failed"); 977a1a4e97bSnorby 978a1a4e97bSnorby if (self) 979f78850efSeric imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0, 980bf2cf305Sclaudio -1, ibuf_data(buf), ibuf_size(buf)); 981a1a4e97bSnorby else 982a1a4e97bSnorby log_warnx("orig_rtr_lsa: empty area %s", 983a1a4e97bSnorby inet_ntoa(area->id)); 984a1a4e97bSnorby 985e39620e5Snicm ibuf_free(buf); 986a1a4e97bSnorby } 987a1a4e97bSnorby 988a1a4e97bSnorby void 989a1a4e97bSnorby orig_net_lsa(struct iface *iface) 990a1a4e97bSnorby { 991a1a4e97bSnorby struct lsa_hdr lsa_hdr; 992a1a4e97bSnorby struct nbr *nbr; 993e39620e5Snicm struct ibuf *buf; 9946663ca32Sstsp struct lsa_net lsa_net; 995a1a4e97bSnorby int num_rtr = 0; 996a1a4e97bSnorby u_int16_t chksum; 997a1a4e97bSnorby 998e39620e5Snicm /* XXX IBUF_READ_SIZE */ 999e39620e5Snicm if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL) 1000a1a4e97bSnorby fatal("orig_net_lsa"); 1001a1a4e97bSnorby 1002bf7812beSclaudio /* reserve space for LSA header and options field */ 1003297c3ba2Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_net)) == -1) 1004297c3ba2Sclaudio fatal("orig_net_lsa: ibuf_add_zero failed"); 1005a1a4e97bSnorby 10066663ca32Sstsp lsa_net.opts = 0; 1007a1a4e97bSnorby /* fully adjacent neighbors + self */ 1008a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) 1009a1a4e97bSnorby if (nbr->state & NBR_STA_FULL) { 1010e39620e5Snicm if (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 1011e39620e5Snicm fatal("orig_net_lsa: ibuf_add failed"); 10123608871eSbluhm lsa_net.opts |= nbr->link_options; 1013a1a4e97bSnorby num_rtr++; 1014a1a4e97bSnorby } 1015a1a4e97bSnorby 1016a1a4e97bSnorby if (num_rtr == 1) { 10172c6b772cSclaudio /* non transit net therefore no need to generate a net lsa */ 1018e39620e5Snicm ibuf_free(buf); 1019a1a4e97bSnorby return; 1020a1a4e97bSnorby } 1021a1a4e97bSnorby 1022a1a4e97bSnorby /* LSA header */ 1023a1a4e97bSnorby if (iface->state & IF_STA_DR) 1024a1a4e97bSnorby lsa_hdr.age = htons(DEFAULT_AGE); 1025a1a4e97bSnorby else 1026a1a4e97bSnorby lsa_hdr.age = htons(MAX_AGE); 1027a1a4e97bSnorby 102867b3ede7Sclaudio lsa_hdr.type = htons(LSA_TYPE_NETWORK); 102967b3ede7Sclaudio /* for network LSAs, the link state ID equals the interface ID */ 103067b3ede7Sclaudio lsa_hdr.ls_id = htonl(iface->ifindex); 1031a1a4e97bSnorby lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 1032a1a4e97bSnorby lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1033bf2cf305Sclaudio lsa_hdr.len = htons(ibuf_size(buf)); 1034a1a4e97bSnorby lsa_hdr.ls_chksum = 0; /* updated later */ 1035297c3ba2Sclaudio if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1) 1036297c3ba2Sclaudio fatal("orig_net_lsa: ibuf_set failed"); 1037a1a4e97bSnorby 10386663ca32Sstsp lsa_net.opts &= lsa_net.opts & htonl(LSA_24_MASK); 1039297c3ba2Sclaudio if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_net, sizeof(lsa_net)) == -1) 1040297c3ba2Sclaudio fatal("orig_net_lsa: ibuf_set failed"); 1041bf7812beSclaudio 1042bf2cf305Sclaudio chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET); 1043297c3ba2Sclaudio if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1) 1044297c3ba2Sclaudio fatal("orig_net_lsa: ibuf_set_n16 failed"); 1045a1a4e97bSnorby 1046f78850efSeric imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0, 1047bf2cf305Sclaudio -1, ibuf_data(buf), ibuf_size(buf)); 1048a1a4e97bSnorby 1049e39620e5Snicm ibuf_free(buf); 1050a1a4e97bSnorby } 1051a1a4e97bSnorby 1052d913b22eSclaudio void 1053d913b22eSclaudio orig_link_lsa(struct iface *iface) 1054d913b22eSclaudio { 1055d913b22eSclaudio struct lsa_hdr lsa_hdr; 1056d913b22eSclaudio struct lsa_link lsa_link; 1057d913b22eSclaudio struct lsa_prefix lsa_prefix; 1058e39620e5Snicm struct ibuf *buf; 1059d913b22eSclaudio struct iface_addr *ia; 1060d913b22eSclaudio struct in6_addr prefix; 1061d913b22eSclaudio unsigned int num_prefix = 0; 1062d913b22eSclaudio u_int16_t chksum; 1063d913b22eSclaudio u_int32_t options; 1064d913b22eSclaudio 1065d913b22eSclaudio log_debug("orig_link_lsa: interface %s", iface->name); 1066d913b22eSclaudio 1067412b2c53Sstsp switch (iface->type) { 1068412b2c53Sstsp case IF_TYPE_VIRTUALLINK: /* forbidden by rfc5340 */ 1069d913b22eSclaudio return; 1070412b2c53Sstsp case IF_TYPE_BROADCAST: 1071412b2c53Sstsp case IF_TYPE_NBMA: 1072d913b22eSclaudio if ((iface->state & IF_STA_MULTI) == 0) 1073d913b22eSclaudio return; 1074412b2c53Sstsp break; 1075412b2c53Sstsp case IF_TYPE_POINTOPOINT: 1076412b2c53Sstsp case IF_TYPE_POINTOMULTIPOINT: 1077412b2c53Sstsp if ((iface->state & IF_STA_POINTTOPOINT) == 0) 1078412b2c53Sstsp return; 1079412b2c53Sstsp break; 1080412b2c53Sstsp default: 1081412b2c53Sstsp fatalx("orig_link_lsa: unknown interface type"); 1082412b2c53Sstsp } 1083d913b22eSclaudio 1084e39620e5Snicm /* XXX IBUF_READ_SIZE */ 1085e39620e5Snicm if ((buf = ibuf_dynamic(sizeof(lsa_hdr) + sizeof(lsa_link), 1086e39620e5Snicm IBUF_READ_SIZE)) == NULL) 1087d913b22eSclaudio fatal("orig_link_lsa"); 1088d913b22eSclaudio 1089d913b22eSclaudio /* reserve space for LSA header and LSA link header */ 1090297c3ba2Sclaudio if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_link)) == -1) 1091297c3ba2Sclaudio fatal("orig_link_lsa: ibuf_add_zero failed"); 1092d913b22eSclaudio 1093d913b22eSclaudio /* link-local address, and all prefixes configured on interface */ 1094d913b22eSclaudio TAILQ_FOREACH(ia, &iface->ifa_list, entry) { 1095d913b22eSclaudio if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) { 1096d913b22eSclaudio log_debug("orig_link_lsa: link local address %s", 1097d913b22eSclaudio log_in6addr(&ia->addr)); 1098d913b22eSclaudio lsa_link.lladdr = ia->addr; 1099d913b22eSclaudio continue; 1100d913b22eSclaudio } 1101d913b22eSclaudio 1102d913b22eSclaudio lsa_prefix.prefixlen = ia->prefixlen; 1103d913b22eSclaudio lsa_prefix.options = 0; 1104d913b22eSclaudio lsa_prefix.metric = 0; 1105d913b22eSclaudio inet6applymask(&prefix, &ia->addr, ia->prefixlen); 1106d913b22eSclaudio log_debug("orig_link_lsa: prefix %s", log_in6addr(&prefix)); 1107e39620e5Snicm if (ibuf_add(buf, &lsa_prefix, sizeof(lsa_prefix))) 1108e39620e5Snicm fatal("orig_link_lsa: ibuf_add failed"); 1109e39620e5Snicm if (ibuf_add(buf, &prefix.s6_addr[0], 1110f3f203f1Sstsp LSA_PREFIXSIZE(ia->prefixlen))) 1111e39620e5Snicm fatal("orig_link_lsa: ibuf_add failed"); 1112d913b22eSclaudio num_prefix++; 1113d913b22eSclaudio } 1114d913b22eSclaudio 1115d913b22eSclaudio /* LSA link header (lladdr has already been filled in above) */ 1116d913b22eSclaudio LSA_24_SETHI(lsa_link.opts, iface->priority); 111777fbfa19Sdenis options = area_ospf_options(iface->area); 1118d913b22eSclaudio LSA_24_SETLO(lsa_link.opts, options); 1119d913b22eSclaudio lsa_link.opts = htonl(lsa_link.opts); 1120d913b22eSclaudio lsa_link.numprefix = htonl(num_prefix); 1121297c3ba2Sclaudio if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_link, sizeof(lsa_link)) == -1) 1122297c3ba2Sclaudio fatal("orig_link_lsa: ibuf_set failed"); 1123d913b22eSclaudio 1124d913b22eSclaudio /* LSA header */ 1125d913b22eSclaudio lsa_hdr.age = htons(DEFAULT_AGE); 1126d913b22eSclaudio lsa_hdr.type = htons(LSA_TYPE_LINK); 1127d913b22eSclaudio /* for link LSAs, the link state ID equals the interface ID */ 1128d913b22eSclaudio lsa_hdr.ls_id = htonl(iface->ifindex); 1129d913b22eSclaudio lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 1130d913b22eSclaudio lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1131bf2cf305Sclaudio lsa_hdr.len = htons(ibuf_size(buf)); 1132d913b22eSclaudio lsa_hdr.ls_chksum = 0; /* updated later */ 1133297c3ba2Sclaudio if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1) 1134297c3ba2Sclaudio fatal("orig_link_lsa: ibuf_set failed"); 1135d913b22eSclaudio 1136bf2cf305Sclaudio chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET); 1137297c3ba2Sclaudio if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1) 1138297c3ba2Sclaudio fatal("orig_link_lsa: ibuf_set_n16 failed"); 1139d913b22eSclaudio 1140f78850efSeric imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0, 1141bf2cf305Sclaudio -1, ibuf_data(buf), ibuf_size(buf)); 1142d913b22eSclaudio 1143e39620e5Snicm ibuf_free(buf); 1144d913b22eSclaudio } 1145d913b22eSclaudio 1146a1a4e97bSnorby u_int32_t 1147a1a4e97bSnorby ospfe_router_id(void) 1148a1a4e97bSnorby { 1149a1a4e97bSnorby return (oeconf->rtr_id.s_addr); 1150a1a4e97bSnorby } 1151a1a4e97bSnorby 1152a1a4e97bSnorby void 1153d7a89a67Sclaudio ospfe_fib_update(int type) 1154a1a4e97bSnorby { 1155a1a4e97bSnorby int old = oe_nofib; 1156a1a4e97bSnorby 1157a1a4e97bSnorby if (type == IMSG_CTL_FIB_COUPLE) 1158a1a4e97bSnorby oe_nofib = 0; 1159a1a4e97bSnorby if (type == IMSG_CTL_FIB_DECOUPLE) 1160a1a4e97bSnorby oe_nofib = 1; 1161a1a4e97bSnorby if (old != oe_nofib) 1162a1a4e97bSnorby orig_rtr_lsa_all(NULL); 1163a1a4e97bSnorby } 1164a1a4e97bSnorby 1165a1a4e97bSnorby void 1166a1a4e97bSnorby ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx) 1167a1a4e97bSnorby { 1168a1a4e97bSnorby struct area *area; 1169a1a4e97bSnorby struct iface *iface; 1170a1a4e97bSnorby struct ctl_iface *ictl; 1171a1a4e97bSnorby 1172a1a4e97bSnorby LIST_FOREACH(area, &oeconf->area_list, entry) 1173a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, entry) 1174a1a4e97bSnorby if (idx == 0 || idx == iface->ifindex) { 1175a1a4e97bSnorby ictl = if_to_ctl(iface); 1176f78850efSeric imsg_compose_event(&c->iev, 11772c6b772cSclaudio IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 11782c6b772cSclaudio ictl, sizeof(struct ctl_iface)); 1179a1a4e97bSnorby } 1180a1a4e97bSnorby } 1181a1a4e97bSnorby 1182a1a4e97bSnorby void 1183a1a4e97bSnorby ospfe_nbr_ctl(struct ctl_conn *c) 1184a1a4e97bSnorby { 1185a1a4e97bSnorby struct area *area; 1186a1a4e97bSnorby struct iface *iface; 1187a1a4e97bSnorby struct nbr *nbr; 1188a1a4e97bSnorby struct ctl_nbr *nctl; 1189a1a4e97bSnorby 1190a1a4e97bSnorby LIST_FOREACH(area, &oeconf->area_list, entry) 1191a1a4e97bSnorby LIST_FOREACH(iface, &area->iface_list, entry) 1192a1a4e97bSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) { 1193a1a4e97bSnorby if (iface->self != nbr) { 1194a1a4e97bSnorby nctl = nbr_to_ctl(nbr); 1195f78850efSeric imsg_compose_event(&c->iev, 1196f78850efSeric IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, 1197a1a4e97bSnorby sizeof(struct ctl_nbr)); 1198a1a4e97bSnorby } 1199a1a4e97bSnorby } 1200a1a4e97bSnorby 1201f78850efSeric imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 1202a1a4e97bSnorby } 1203a1a4e97bSnorby 1204a1a4e97bSnorby void 1205a1a4e97bSnorby ospfe_demote_area(struct area *area, int active) 1206a1a4e97bSnorby { 1207a1a4e97bSnorby struct demote_msg dmsg; 1208a1a4e97bSnorby 1209a1a4e97bSnorby if (ospfd_process != PROC_OSPF_ENGINE || 1210a1a4e97bSnorby area->demote_group[0] == '\0') 1211a1a4e97bSnorby return; 1212a1a4e97bSnorby 1213a1a4e97bSnorby bzero(&dmsg, sizeof(dmsg)); 1214a1a4e97bSnorby strlcpy(dmsg.demote_group, area->demote_group, 1215a1a4e97bSnorby sizeof(dmsg.demote_group)); 1216a1a4e97bSnorby dmsg.level = area->demote_level; 1217a1a4e97bSnorby if (active) 1218a1a4e97bSnorby dmsg.level = -dmsg.level; 1219a1a4e97bSnorby 1220a1a4e97bSnorby ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1221a1a4e97bSnorby } 1222a1a4e97bSnorby 1223a1a4e97bSnorby void 1224a1a4e97bSnorby ospfe_demote_iface(struct iface *iface, int active) 1225a1a4e97bSnorby { 1226a1a4e97bSnorby struct demote_msg dmsg; 1227a1a4e97bSnorby 1228a1a4e97bSnorby if (ospfd_process != PROC_OSPF_ENGINE || 1229a1a4e97bSnorby iface->demote_group[0] == '\0') 1230a1a4e97bSnorby return; 1231a1a4e97bSnorby 1232a1a4e97bSnorby bzero(&dmsg, sizeof(dmsg)); 1233a1a4e97bSnorby strlcpy(dmsg.demote_group, iface->demote_group, 1234a1a4e97bSnorby sizeof(dmsg.demote_group)); 1235a1a4e97bSnorby if (active) 1236a1a4e97bSnorby dmsg.level = -1; 1237a1a4e97bSnorby else 1238a1a4e97bSnorby dmsg.level = 1; 1239a1a4e97bSnorby 12402c6b772cSclaudio log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group, 12412c6b772cSclaudio dmsg.level); 12422c6b772cSclaudio 1243a1a4e97bSnorby ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1244a1a4e97bSnorby } 1245