4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2008 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/types.h>
28 #include <arpa/inet.h>
37 static void ldpe_sig_handler(int, short, void *);
38 static __dead
void ldpe_shutdown(void);
39 static void ldpe_dispatch_main(int, short, void *);
40 static void ldpe_dispatch_lde(int, short, void *);
41 static void ldpe_dispatch_pfkey(int, short, void *);
42 static void ldpe_setup_sockets(int, int, int, int);
43 static void ldpe_close_sockets(int);
44 static void ldpe_iface_af_ctl(struct ctl_conn
*, int, unsigned int);
46 struct ldpd_conf
*leconf
;
47 struct ldpd_sysdep sysdep
;
49 static struct imsgev
*iev_main
;
50 static struct imsgev
*iev_lde
;
51 static struct event pfkey_ev
;
55 ldpe_sig_handler(int sig
, short event
, void *bula
)
63 fatalx("unexpected signal");
67 /* label distribution protocol engine */
69 ldpe(int debug
, int verbose
)
72 struct event ev_sigint
, ev_sigterm
;
74 leconf
= config_new_empty();
79 setproctitle("ldp engine");
80 ldpd_process
= PROC_LDP_ENGINE
;
82 /* create ldpd control socket outside chroot */
83 if (control_init() == -1)
84 fatalx("control socket setup failed");
86 LIST_INIT(&global
.addr_list
);
87 LIST_INIT(&global
.adj_list
);
88 TAILQ_INIT(&global
.pending_conns
);
89 if (inet_pton(AF_INET
, AllRouters_v4
, &global
.mcast_addr_v4
) != 1)
91 if (inet_pton(AF_INET6
, AllRouters_v6
, &global
.mcast_addr_v6
) != 1)
93 global
.pfkeysock
= pfkey_init();
95 if ((pw
= getpwnam(LDPD_USER
)) == NULL
)
98 if (chroot(pw
->pw_dir
) == -1)
100 if (chdir("/") == -1)
101 fatal("chdir(\"/\")");
103 if (setgroups(1, &pw
->pw_gid
) ||
104 setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) ||
105 setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
))
106 fatal("can't drop privileges");
108 if (pledge("stdio cpath inet mcast recvfd", NULL
) == -1)
114 /* setup signal handler */
115 signal_set(&ev_sigint
, SIGINT
, ldpe_sig_handler
, NULL
);
116 signal_set(&ev_sigterm
, SIGTERM
, ldpe_sig_handler
, NULL
);
117 signal_add(&ev_sigint
, NULL
);
118 signal_add(&ev_sigterm
, NULL
);
119 signal(SIGPIPE
, SIG_IGN
);
120 signal(SIGHUP
, SIG_IGN
);
122 /* setup pipe and event handler to the parent process */
123 if ((iev_main
= malloc(sizeof(struct imsgev
))) == NULL
)
125 imsg_init(&iev_main
->ibuf
, 3);
126 iev_main
->handler
= ldpe_dispatch_main
;
127 iev_main
->events
= EV_READ
;
128 event_set(&iev_main
->ev
, iev_main
->ibuf
.fd
, iev_main
->events
,
129 iev_main
->handler
, iev_main
);
130 event_add(&iev_main
->ev
, NULL
);
132 if (sysdep
.no_pfkey
== 0) {
133 event_set(&pfkey_ev
, global
.pfkeysock
, EV_READ
| EV_PERSIST
,
134 ldpe_dispatch_pfkey
, NULL
);
135 event_add(&pfkey_ev
, NULL
);
138 /* mark sockets as closed */
139 global
.ipv4
.ldp_disc_socket
= -1;
140 global
.ipv4
.ldp_edisc_socket
= -1;
141 global
.ipv4
.ldp_session_socket
= -1;
142 global
.ipv6
.ldp_disc_socket
= -1;
143 global
.ipv6
.ldp_edisc_socket
= -1;
144 global
.ipv6
.ldp_session_socket
= -1;
146 /* listen on ldpd control socket */
147 TAILQ_INIT(&ctl_conns
);
150 if ((pkt_ptr
= calloc(1, IBUF_READ_SIZE
)) == NULL
)
161 struct if_addr
*if_addr
;
165 msgbuf_write(&iev_lde
->ibuf
.w
);
166 msgbuf_clear(&iev_lde
->ibuf
.w
);
167 close(iev_lde
->ibuf
.fd
);
168 msgbuf_write(&iev_main
->ibuf
.w
);
169 msgbuf_clear(&iev_main
->ibuf
.w
);
170 close(iev_main
->ibuf
.fd
);
173 config_clear(leconf
);
175 if (sysdep
.no_pfkey
== 0) {
176 event_del(&pfkey_ev
);
177 close(global
.pfkeysock
);
179 ldpe_close_sockets(AF_INET
);
180 ldpe_close_sockets(AF_INET6
);
182 /* remove addresses from global list */
183 while ((if_addr
= LIST_FIRST(&global
.addr_list
)) != NULL
) {
184 LIST_REMOVE(if_addr
, entry
);
187 while ((adj
= LIST_FIRST(&global
.adj_list
)) != NULL
)
188 adj_del(adj
, S_SHUTDOWN
);
195 log_info("ldp engine exiting");
201 ldpe_imsg_compose_parent(int type
, pid_t pid
, void *data
, uint16_t datalen
)
203 return (imsg_compose_event(iev_main
, type
, 0, pid
, -1, data
, datalen
));
207 ldpe_imsg_compose_lde(int type
, uint32_t peerid
, pid_t pid
, void *data
,
210 return (imsg_compose_event(iev_lde
, type
, peerid
, pid
, -1,
216 ldpe_dispatch_main(int fd
, short event
, void *bula
)
218 static struct ldpd_conf
*nconf
;
219 struct iface
*niface
;
221 struct nbr_params
*nnbrp
;
222 static struct l2vpn
*nl2vpn
;
223 struct l2vpn_if
*nlif
;
224 struct l2vpn_pw
*npw
;
226 struct imsgev
*iev
= bula
;
227 struct imsgbuf
*ibuf
= &iev
->ibuf
;
228 struct iface
*iface
= NULL
;
231 enum socket_type
*socket_type
;
232 static int disc_socket
= -1;
233 static int edisc_socket
= -1;
234 static int session_socket
= -1;
236 struct nbr_params
*nbrp
;
239 if (event
& EV_READ
) {
240 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
241 fatal("imsg_read error");
242 if (n
== 0) /* connection closed */
245 if (event
& EV_WRITE
) {
246 if ((n
= msgbuf_write(&ibuf
->w
)) == -1 && errno
!= EAGAIN
)
247 fatal("ldpe_dispatch_main: msgbuf_write");
253 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
254 fatal("ldpe_dispatch_main: imsg_get error");
258 switch (imsg
.hdr
.type
) {
260 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
262 fatalx("IFSTATUS imsg with wrong len");
265 iface
= if_lookup(leconf
, kif
->ifindex
);
269 iface
->flags
= kif
->flags
;
270 iface
->linkstate
= kif
->link_state
;
271 if_update(iface
, AF_UNSPEC
);
274 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
275 sizeof(struct kaddr
))
276 fatalx("NEWADDR imsg with wrong len");
278 if_addr_add(imsg
.data
);
281 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
282 sizeof(struct kaddr
))
283 fatalx("DELADDR imsg with wrong len");
285 if_addr_del(imsg
.data
);
287 case IMSG_SOCKET_IPC
:
289 log_warnx("%s: received unexpected imsg fd "
293 if ((fd
= imsg
.fd
) == -1) {
294 log_warnx("%s: expected to receive imsg fd to "
295 "lde but didn't receive any", __func__
);
299 if ((iev_lde
= malloc(sizeof(struct imsgev
))) == NULL
)
301 imsg_init(&iev_lde
->ibuf
, fd
);
302 iev_lde
->handler
= ldpe_dispatch_lde
;
303 iev_lde
->events
= EV_READ
;
304 event_set(&iev_lde
->ev
, iev_lde
->ibuf
.fd
,
305 iev_lde
->events
, iev_lde
->handler
, iev_lde
);
306 event_add(&iev_lde
->ev
, NULL
);
308 case IMSG_CLOSE_SOCKETS
:
309 af
= imsg
.hdr
.peerid
;
311 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
314 session_shutdown(nbr
, S_SHUTDOWN
, 0, 0);
317 ldpe_close_sockets(af
);
324 if ((ldp_af_conf_get(leconf
, af
))->flags
&
326 ldpe_imsg_compose_parent(IMSG_REQUEST_SOCKETS
,
329 case IMSG_SOCKET_NET
:
330 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
331 sizeof(enum socket_type
))
332 fatalx("SOCKET_NET imsg with wrong len");
333 socket_type
= imsg
.data
;
335 switch (*socket_type
) {
336 case LDP_SOCKET_DISC
:
337 disc_socket
= imsg
.fd
;
339 case LDP_SOCKET_EDISC
:
340 edisc_socket
= imsg
.fd
;
342 case LDP_SOCKET_SESSION
:
343 session_socket
= imsg
.fd
;
347 case IMSG_SETUP_SOCKETS
:
348 af
= imsg
.hdr
.peerid
;
349 if (disc_socket
== -1 || edisc_socket
== -1 ||
350 session_socket
== -1) {
351 if (disc_socket
!= -1)
353 if (edisc_socket
!= -1)
355 if (session_socket
!= -1)
356 close(session_socket
);
360 ldpe_setup_sockets(af
, disc_socket
, edisc_socket
,
364 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
367 nbr
->laddr
= (ldp_af_conf_get(leconf
,
369 nbrp
= nbr_params_find(leconf
, nbr
->id
);
370 if (nbrp
&& pfkey_establish(nbr
, nbrp
) == -1)
371 fatalx("pfkey setup failed");
372 if (nbr_session_active_role(nbr
))
373 nbr_establish_connection(nbr
);
376 case IMSG_RECONF_CONF
:
377 if ((nconf
= malloc(sizeof(struct ldpd_conf
))) ==
380 memcpy(nconf
, imsg
.data
, sizeof(struct ldpd_conf
));
382 LIST_INIT(&nconf
->iface_list
);
383 LIST_INIT(&nconf
->tnbr_list
);
384 LIST_INIT(&nconf
->nbrp_list
);
385 LIST_INIT(&nconf
->l2vpn_list
);
387 case IMSG_RECONF_IFACE
:
388 if ((niface
= malloc(sizeof(struct iface
))) == NULL
)
390 memcpy(niface
, imsg
.data
, sizeof(struct iface
));
392 LIST_INIT(&niface
->addr_list
);
393 LIST_INIT(&niface
->ipv4
.adj_list
);
394 LIST_INIT(&niface
->ipv6
.adj_list
);
395 niface
->ipv4
.iface
= niface
;
396 niface
->ipv6
.iface
= niface
;
398 LIST_INSERT_HEAD(&nconf
->iface_list
, niface
, entry
);
400 case IMSG_RECONF_TNBR
:
401 if ((ntnbr
= malloc(sizeof(struct tnbr
))) == NULL
)
403 memcpy(ntnbr
, imsg
.data
, sizeof(struct tnbr
));
405 LIST_INSERT_HEAD(&nconf
->tnbr_list
, ntnbr
, entry
);
407 case IMSG_RECONF_NBRP
:
408 if ((nnbrp
= malloc(sizeof(struct nbr_params
))) == NULL
)
410 memcpy(nnbrp
, imsg
.data
, sizeof(struct nbr_params
));
412 LIST_INSERT_HEAD(&nconf
->nbrp_list
, nnbrp
, entry
);
414 case IMSG_RECONF_L2VPN
:
415 if ((nl2vpn
= malloc(sizeof(struct l2vpn
))) == NULL
)
417 memcpy(nl2vpn
, imsg
.data
, sizeof(struct l2vpn
));
419 LIST_INIT(&nl2vpn
->if_list
);
420 LIST_INIT(&nl2vpn
->pw_list
);
422 LIST_INSERT_HEAD(&nconf
->l2vpn_list
, nl2vpn
, entry
);
424 case IMSG_RECONF_L2VPN_IF
:
425 if ((nlif
= malloc(sizeof(struct l2vpn_if
))) == NULL
)
427 memcpy(nlif
, imsg
.data
, sizeof(struct l2vpn_if
));
429 nlif
->l2vpn
= nl2vpn
;
430 LIST_INSERT_HEAD(&nl2vpn
->if_list
, nlif
, entry
);
432 case IMSG_RECONF_L2VPN_PW
:
433 if ((npw
= malloc(sizeof(struct l2vpn_pw
))) == NULL
)
435 memcpy(npw
, imsg
.data
, sizeof(struct l2vpn_pw
));
438 LIST_INSERT_HEAD(&nl2vpn
->pw_list
, npw
, entry
);
440 case IMSG_RECONF_END
:
441 merge_config(leconf
, nconf
);
443 global
.conf_seqnum
++;
445 case IMSG_CTL_KROUTE
:
446 case IMSG_CTL_KROUTE_ADDR
:
447 case IMSG_CTL_IFINFO
:
449 control_imsg_relay(&imsg
);
452 log_debug("ldpe_dispatch_main: error handling imsg %d",
461 /* this pipe is dead, so remove the event handler */
463 event_loopexit(NULL
);
469 ldpe_dispatch_lde(int fd
, short event
, void *bula
)
471 struct imsgev
*iev
= bula
;
472 struct imsgbuf
*ibuf
= &iev
->ibuf
;
475 struct notify_msg nm
;
477 struct nbr
*nbr
= NULL
;
479 if (event
& EV_READ
) {
480 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
481 fatal("imsg_read error");
482 if (n
== 0) /* connection closed */
485 if (event
& EV_WRITE
) {
486 if ((n
= msgbuf_write(&ibuf
->w
)) == -1 && errno
!= EAGAIN
)
487 fatal("ldpe_dispatch_lde: msgbuf_write");
493 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
494 fatal("ldpe_dispatch_lde: imsg_get error");
498 switch (imsg
.hdr
.type
) {
499 case IMSG_MAPPING_ADD
:
500 case IMSG_RELEASE_ADD
:
501 case IMSG_REQUEST_ADD
:
502 case IMSG_WITHDRAW_ADD
:
503 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= sizeof(map
))
504 fatalx("invalid size of map request");
505 memcpy(&map
, imsg
.data
, sizeof(map
));
507 nbr
= nbr_find_peerid(imsg
.hdr
.peerid
);
509 log_debug("ldpe_dispatch_lde: cannot find "
513 if (nbr
->state
!= NBR_STA_OPER
)
516 switch (imsg
.hdr
.type
) {
517 case IMSG_MAPPING_ADD
:
518 mapping_list_add(&nbr
->mapping_list
, &map
);
520 case IMSG_RELEASE_ADD
:
521 mapping_list_add(&nbr
->release_list
, &map
);
523 case IMSG_REQUEST_ADD
:
524 mapping_list_add(&nbr
->request_list
, &map
);
526 case IMSG_WITHDRAW_ADD
:
527 mapping_list_add(&nbr
->withdraw_list
, &map
);
531 case IMSG_MAPPING_ADD_END
:
532 case IMSG_RELEASE_ADD_END
:
533 case IMSG_REQUEST_ADD_END
:
534 case IMSG_WITHDRAW_ADD_END
:
535 nbr
= nbr_find_peerid(imsg
.hdr
.peerid
);
537 log_debug("ldpe_dispatch_lde: cannot find "
541 if (nbr
->state
!= NBR_STA_OPER
)
544 switch (imsg
.hdr
.type
) {
545 case IMSG_MAPPING_ADD_END
:
546 send_labelmessage(nbr
, MSG_TYPE_LABELMAPPING
,
549 case IMSG_RELEASE_ADD_END
:
550 send_labelmessage(nbr
, MSG_TYPE_LABELRELEASE
,
553 case IMSG_REQUEST_ADD_END
:
554 send_labelmessage(nbr
, MSG_TYPE_LABELREQUEST
,
557 case IMSG_WITHDRAW_ADD_END
:
558 send_labelmessage(nbr
, MSG_TYPE_LABELWITHDRAW
,
559 &nbr
->withdraw_list
);
563 case IMSG_NOTIFICATION_SEND
:
564 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= sizeof(nm
))
565 fatalx("invalid size of OE request");
566 memcpy(&nm
, imsg
.data
, sizeof(nm
));
568 nbr
= nbr_find_peerid(imsg
.hdr
.peerid
);
570 log_debug("ldpe_dispatch_lde: cannot find "
574 if (nbr
->state
!= NBR_STA_OPER
)
577 send_notification_full(nbr
->tcp
, &nm
);
580 case IMSG_CTL_SHOW_LIB
:
581 case IMSG_CTL_SHOW_L2VPN_PW
:
582 case IMSG_CTL_SHOW_L2VPN_BINDING
:
583 control_imsg_relay(&imsg
);
586 log_debug("ldpe_dispatch_lde: error handling imsg %d",
595 /* this pipe is dead, so remove the event handler */
597 event_loopexit(NULL
);
603 ldpe_dispatch_pfkey(int fd
, short event
, void *bula
)
605 if (event
& EV_READ
) {
606 if (pfkey_read(fd
, NULL
) == -1) {
607 fatal("pfkey_read failed, exiting...");
613 ldpe_setup_sockets(int af
, int disc_socket
, int edisc_socket
,
616 struct ldpd_af_global
*af_global
;
618 af_global
= ldp_af_global_get(&global
, af
);
620 /* discovery socket */
621 af_global
->ldp_disc_socket
= disc_socket
;
622 event_set(&af_global
->disc_ev
, af_global
->ldp_disc_socket
,
623 EV_READ
|EV_PERSIST
, disc_recv_packet
, NULL
);
624 event_add(&af_global
->disc_ev
, NULL
);
626 /* extended discovery socket */
627 af_global
->ldp_edisc_socket
= edisc_socket
;
628 event_set(&af_global
->edisc_ev
, af_global
->ldp_edisc_socket
,
629 EV_READ
|EV_PERSIST
, disc_recv_packet
, NULL
);
630 event_add(&af_global
->edisc_ev
, NULL
);
633 af_global
->ldp_session_socket
= session_socket
;
634 accept_add(af_global
->ldp_session_socket
, session_accept
, NULL
);
638 ldpe_close_sockets(int af
)
640 struct ldpd_af_global
*af_global
;
642 af_global
= ldp_af_global_get(&global
, af
);
644 /* discovery socket */
645 if (event_initialized(&af_global
->disc_ev
))
646 event_del(&af_global
->disc_ev
);
647 if (af_global
->ldp_disc_socket
!= -1) {
648 close(af_global
->ldp_disc_socket
);
649 af_global
->ldp_disc_socket
= -1;
652 /* extended discovery socket */
653 if (event_initialized(&af_global
->edisc_ev
))
654 event_del(&af_global
->edisc_ev
);
655 if (af_global
->ldp_edisc_socket
!= -1) {
656 close(af_global
->ldp_edisc_socket
);
657 af_global
->ldp_edisc_socket
= -1;
661 if (af_global
->ldp_session_socket
!= -1) {
662 accept_del(af_global
->ldp_session_socket
);
663 close(af_global
->ldp_session_socket
);
664 af_global
->ldp_session_socket
= -1;
669 ldpe_reset_nbrs(int af
)
673 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
675 session_shutdown(nbr
, S_SHUTDOWN
, 0, 0);
680 ldpe_reset_ds_nbrs(void)
684 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
686 session_shutdown(nbr
, S_SHUTDOWN
, 0, 0);
691 ldpe_remove_dynamic_tnbrs(int af
)
693 struct tnbr
*tnbr
, *safe
;
695 LIST_FOREACH_SAFE(tnbr
, &leconf
->tnbr_list
, entry
, safe
) {
699 tnbr
->flags
&= ~F_TNBR_DYNAMIC
;
705 ldpe_stop_init_backoff(int af
)
709 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
710 if (nbr
->af
== af
&& nbr_pending_idtimer(nbr
)) {
711 nbr_stop_idtimer(nbr
);
712 nbr_establish_connection(nbr
);
718 ldpe_iface_af_ctl(struct ctl_conn
*c
, int af
, unsigned int idx
)
722 struct ctl_iface
*ictl
;
724 LIST_FOREACH(iface
, &leconf
->iface_list
, entry
) {
725 if (idx
== 0 || idx
== iface
->ifindex
) {
726 ia
= iface_af_get(iface
, af
);
730 ictl
= if_to_ctl(ia
);
731 imsg_compose_event(&c
->iev
,
732 IMSG_CTL_SHOW_INTERFACE
,
733 0, 0, -1, ictl
, sizeof(struct ctl_iface
));
739 ldpe_iface_ctl(struct ctl_conn
*c
, unsigned int idx
)
741 ldpe_iface_af_ctl(c
, AF_INET
, idx
);
742 ldpe_iface_af_ctl(c
, AF_INET6
, idx
);
746 ldpe_adj_ctl(struct ctl_conn
*c
)
750 struct ctl_adj
*actl
;
752 RB_FOREACH(nbr
, nbr_addr_head
, &nbrs_by_addr
) {
753 LIST_FOREACH(adj
, &nbr
->adj_list
, nbr_entry
) {
754 actl
= adj_to_ctl(adj
);
755 imsg_compose_event(&c
->iev
, IMSG_CTL_SHOW_DISCOVERY
,
756 0, 0, -1, actl
, sizeof(struct ctl_adj
));
759 /* show adjacencies not associated with any neighbor */
760 LIST_FOREACH(adj
, &global
.adj_list
, global_entry
) {
761 if (adj
->nbr
!= NULL
)
764 actl
= adj_to_ctl(adj
);
765 imsg_compose_event(&c
->iev
, IMSG_CTL_SHOW_DISCOVERY
, 0, 0,
766 -1, actl
, sizeof(struct ctl_adj
));
769 imsg_compose_event(&c
->iev
, IMSG_CTL_END
, 0, 0, -1, NULL
, 0);
773 ldpe_nbr_ctl(struct ctl_conn
*c
)
776 struct ctl_nbr
*nctl
;
778 RB_FOREACH(nbr
, nbr_addr_head
, &nbrs_by_addr
) {
779 nctl
= nbr_to_ctl(nbr
);
780 imsg_compose_event(&c
->iev
, IMSG_CTL_SHOW_NBR
, 0, 0, -1, nctl
,
781 sizeof(struct ctl_nbr
));
783 imsg_compose_event(&c
->iev
, IMSG_CTL_END
, 0, 0, -1, NULL
, 0);
787 mapping_list_add(struct mapping_head
*mh
, struct map
*map
)
789 struct mapping_entry
*me
;
791 me
= calloc(1, sizeof(*me
));
796 TAILQ_INSERT_TAIL(mh
, me
, entry
);
800 mapping_list_clr(struct mapping_head
*mh
)
802 struct mapping_entry
*me
;
804 while ((me
= TAILQ_FIRST(mh
)) != NULL
) {
805 TAILQ_REMOVE(mh
, me
, entry
);