File: | src/usr.sbin/dvmrpd/dvmrpe.c |
Warning: | line 450, column 7 Potential leak of memory pointed to by 'rr' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dvmrpe.c,v 1.23 2021/01/19 12:29:46 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> | |||
5 | * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> | |||
6 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||
7 | * | |||
8 | * Permission to use, copy, modify, and distribute this software for any | |||
9 | * purpose with or without fee is hereby granted, provided that the above | |||
10 | * copyright notice and this permission notice appear in all copies. | |||
11 | * | |||
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
19 | */ | |||
20 | ||||
21 | #include <sys/types.h> | |||
22 | #include <sys/socket.h> | |||
23 | #include <sys/queue.h> | |||
24 | #include <netinet/in.h> | |||
25 | #include <arpa/inet.h> | |||
26 | #include <net/if_types.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <signal.h> | |||
29 | #include <string.h> | |||
30 | #include <fcntl.h> | |||
31 | #include <pwd.h> | |||
32 | #include <unistd.h> | |||
33 | #include <event.h> | |||
34 | #include <err.h> | |||
35 | #include <errno(*__errno()).h> | |||
36 | #include <stdio.h> | |||
37 | ||||
38 | #include "igmp.h" | |||
39 | #include "dvmrp.h" | |||
40 | #include "dvmrpd.h" | |||
41 | #include "dvmrpe.h" | |||
42 | #include "control.h" | |||
43 | #include "log.h" | |||
44 | ||||
45 | void dvmrpe_sig_handler(int, short, void *); | |||
46 | __dead__attribute__((__noreturn__)) void dvmrpe_shutdown(void); | |||
47 | ||||
48 | volatile sig_atomic_t dvmrpe_quit = 0; | |||
49 | struct dvmrpd_conf *deconf = NULL((void *)0); | |||
50 | static struct imsgev *iev_main; | |||
51 | static struct imsgev *iev_rde; | |||
52 | ||||
53 | void | |||
54 | dvmrpe_sig_handler(int sig, short event, void *bula) | |||
55 | { | |||
56 | switch (sig) { | |||
57 | case SIGINT2: | |||
58 | case SIGTERM15: | |||
59 | dvmrpe_shutdown(); | |||
60 | /* NOTREACHED */ | |||
61 | default: | |||
62 | fatalx("unexpected signal"); | |||
63 | } | |||
64 | } | |||
65 | ||||
66 | /* dvmrp engine */ | |||
67 | pid_t | |||
68 | dvmrpe(struct dvmrpd_conf *xconf, int pipe_parent2dvmrpe[2], | |||
69 | int pipe_dvmrpe2rde[2], int pipe_parent2rde[2]) | |||
70 | { | |||
71 | struct iface *iface = NULL((void *)0); | |||
72 | struct passwd *pw; | |||
73 | struct event ev_sigint, ev_sigterm; | |||
74 | pid_t pid; | |||
75 | ||||
76 | switch (pid = fork()) { | |||
77 | case -1: | |||
78 | fatal("cannot fork"); | |||
79 | case 0: | |||
80 | break; | |||
81 | default: | |||
82 | ||||
83 | return (pid); | |||
84 | } | |||
85 | ||||
86 | /* create the raw ip socket */ | |||
87 | if ((xconf->dvmrp_socket = socket(AF_INET2, | |||
88 | SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
89 | IPPROTO_IGMP2)) == -1) | |||
90 | fatal("error creating raw socket"); | |||
91 | ||||
92 | /* create dvmrpd control socket outside chroot */ | |||
93 | if (control_init() == -1) | |||
94 | fatalx("control socket setup failed"); | |||
95 | ||||
96 | /* set some defaults */ | |||
97 | if (if_set_mcast_ttl(xconf->dvmrp_socket, | |||
98 | IP_DEFAULT_MULTICAST_TTL1) == -1) | |||
99 | fatal("if_set_mcast_ttl"); | |||
100 | ||||
101 | if (if_set_mcast_loop(xconf->dvmrp_socket) == -1) | |||
102 | fatal("if_set_mcast_loop"); | |||
103 | ||||
104 | if (if_set_tos(xconf->dvmrp_socket, IPTOS_PREC_INTERNETCONTROL0xc0) == -1) | |||
105 | fatal("if_set_tos"); | |||
106 | ||||
107 | if_set_recvbuf(xconf->dvmrp_socket); | |||
108 | ||||
109 | deconf = xconf; | |||
110 | ||||
111 | if ((pw = getpwnam(DVMRPD_USER"_dvmrpd")) == NULL((void *)0)) | |||
112 | fatal("getpwnam"); | |||
113 | ||||
114 | if (chroot(pw->pw_dir) == -1) | |||
115 | fatal("chroot"); | |||
116 | if (chdir("/") == -1) | |||
117 | fatal("chdir(\"/\")"); | |||
118 | ||||
119 | setproctitle("dvmrp engine"); | |||
120 | log_procname = "dvmrpe"; | |||
121 | ||||
122 | if (setgroups(1, &pw->pw_gid) || | |||
123 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | |||
124 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | |||
125 | fatal("can't drop privileges"); | |||
126 | ||||
127 | event_init(); | |||
128 | nbr_init(NBR_HASHSIZE128); | |||
129 | ||||
130 | /* setup signal handler */ | |||
131 | signal_set(&ev_sigint, SIGINT, dvmrpe_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, dvmrpe_sig_handler, ( (void *)0)); | |||
132 | signal_set(&ev_sigterm, SIGTERM, dvmrpe_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, dvmrpe_sig_handler, ((void *)0)); | |||
133 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); | |||
134 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); | |||
135 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); | |||
136 | ||||
137 | /* setup pipes */ | |||
138 | close(pipe_parent2dvmrpe[0]); | |||
139 | close(pipe_dvmrpe2rde[1]); | |||
140 | close(pipe_parent2rde[0]); | |||
141 | close(pipe_parent2rde[1]); | |||
142 | ||||
143 | if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL((void *)0) || | |||
144 | (iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0)) | |||
145 | fatal(NULL((void *)0)); | |||
146 | imsg_init(&iev_rde->ibuf, pipe_dvmrpe2rde[0]); | |||
147 | iev_rde->handler = dvmrpe_dispatch_rde; | |||
148 | ||||
149 | imsg_init(&iev_main->ibuf, pipe_parent2dvmrpe[1]); | |||
150 | iev_main->handler = dvmrpe_dispatch_main; | |||
151 | ||||
152 | /* setup event handler */ | |||
153 | iev_rde->events = EV_READ0x02; | |||
154 | event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, | |||
155 | iev_rde->handler, iev_rde); | |||
156 | event_add(&iev_rde->ev, NULL((void *)0)); | |||
157 | ||||
158 | iev_main->events = EV_READ0x02; | |||
159 | event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, | |||
160 | iev_main->handler, iev_main); | |||
161 | event_add(&iev_main->ev, NULL((void *)0)); | |||
162 | ||||
163 | event_set(&deconf->ev, deconf->dvmrp_socket, EV_READ0x02|EV_PERSIST0x10, | |||
164 | recv_packet, deconf); | |||
165 | event_add(&deconf->ev, NULL((void *)0)); | |||
166 | ||||
167 | /* listen on dvmrpd control socket */ | |||
168 | control_listen(); | |||
169 | ||||
170 | /* start interfaces */ | |||
171 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
172 | if_init(xconf, iface); | |||
173 | if (if_fsm(iface, IF_EVT_UP)) { | |||
174 | log_debug("error starting interface %s", iface->name); | |||
175 | } | |||
176 | } | |||
177 | ||||
178 | evtimer_set(&deconf->report_timer, report_timer, deconf)event_set(&deconf->report_timer, -1, 0, report_timer, deconf ); | |||
179 | start_report_timer(); | |||
180 | ||||
181 | event_dispatch(); | |||
182 | ||||
183 | dvmrpe_shutdown(); | |||
184 | /* NOTREACHED */ | |||
185 | return (0); | |||
186 | } | |||
187 | ||||
188 | __dead__attribute__((__noreturn__)) void | |||
189 | dvmrpe_shutdown(void) | |||
190 | { | |||
191 | struct iface *iface; | |||
192 | ||||
193 | /* close pipes */ | |||
194 | msgbuf_write(&iev_rde->ibuf.w); | |||
195 | msgbuf_clear(&iev_rde->ibuf.w); | |||
196 | close(iev_rde->ibuf.fd); | |||
197 | msgbuf_write(&iev_main->ibuf.w); | |||
198 | msgbuf_clear(&iev_main->ibuf.w); | |||
199 | close(iev_main->ibuf.fd); | |||
200 | ||||
201 | /* stop all interfaces and delete them */ | |||
202 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
203 | if (if_fsm(iface, IF_EVT_DOWN)) { | |||
204 | log_debug("error stopping interface %s", | |||
205 | iface->name); | |||
206 | } | |||
207 | if_del(iface); | |||
208 | } | |||
209 | ||||
210 | /* clean up */ | |||
211 | free(iev_rde); | |||
212 | free(iev_main); | |||
213 | ||||
214 | log_info("dvmrp engine exiting"); | |||
215 | _exit(0); | |||
216 | } | |||
217 | ||||
218 | int | |||
219 | dvmrpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) | |||
220 | { | |||
221 | return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); | |||
222 | } | |||
223 | ||||
224 | int | |||
225 | dvmrpe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, | |||
226 | void *data, u_int16_t datalen) | |||
227 | { | |||
228 | return (imsg_compose_event(iev_rde, type, peerid, pid, | |||
229 | -1, data, datalen)); | |||
230 | } | |||
231 | ||||
232 | void | |||
233 | dvmrpe_dispatch_main(int fd, short event, void *bula) | |||
234 | { | |||
235 | struct imsg imsg; | |||
236 | struct imsgev *iev = bula; | |||
237 | struct imsgbuf *ibuf = &iev->ibuf; | |||
238 | struct kif *kif; | |||
239 | struct iface *iface; | |||
240 | ssize_t n; | |||
241 | int shut = 0, link_ok; | |||
242 | ||||
243 | if (event & EV_READ0x02) { | |||
244 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
245 | fatal("imsg_read error"); | |||
246 | if (n == 0) /* connection closed */ | |||
247 | shut = 1; | |||
248 | } | |||
249 | if (event & EV_WRITE0x04) { | |||
250 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
251 | fatal("msgbuf_write"); | |||
252 | if (n == 0) /* connection closed */ | |||
253 | shut = 1; | |||
254 | } | |||
255 | ||||
256 | for (;;) { | |||
257 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
258 | fatal("dvmrpe_dispatch_main: imsg_read error"); | |||
259 | if (n == 0) | |||
260 | break; | |||
261 | ||||
262 | switch (imsg.hdr.type) { | |||
263 | case IMSG_IFINFO: | |||
264 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != | |||
265 | sizeof(struct kif)) | |||
266 | fatalx("IFINFO imsg with wrong len"); | |||
267 | kif = imsg.data; | |||
268 | link_ok = (kif->flags & IFF_UP0x1) && | |||
269 | LINK_STATE_IS_UP(kif->link_state)((kif->link_state) >= 4 || (kif->link_state) == 0); | |||
270 | ||||
271 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
272 | if (kif->ifindex == iface->ifindex) { | |||
273 | iface->flags = kif->flags; | |||
274 | iface->linkstate = kif->link_state; | |||
275 | ||||
276 | if (link_ok) { | |||
277 | if_fsm(iface, IF_EVT_UP); | |||
278 | log_warnx("interface %s up", | |||
279 | iface->name); | |||
280 | } else { | |||
281 | if_fsm(iface, IF_EVT_DOWN); | |||
282 | log_warnx("interface %s down", | |||
283 | iface->name); | |||
284 | } | |||
285 | } | |||
286 | } | |||
287 | break; | |||
288 | default: | |||
289 | log_debug("dvmrpe_dispatch_main: error handling " | |||
290 | "imsg %d", imsg.hdr.type); | |||
291 | break; | |||
292 | } | |||
293 | imsg_free(&imsg); | |||
294 | } | |||
295 | if (!shut) | |||
296 | imsg_event_add(iev); | |||
297 | else { | |||
298 | /* this pipe is dead, so remove the event handler */ | |||
299 | event_del(&iev->ev); | |||
300 | event_loopexit(NULL((void *)0)); | |||
301 | } | |||
302 | } | |||
303 | ||||
304 | void | |||
305 | dvmrpe_dispatch_rde(int fd, short event, void *bula) | |||
306 | { | |||
307 | struct imsgev *iev = bula; | |||
308 | struct imsgbuf *ibuf = &iev->ibuf; | |||
309 | struct imsg imsg; | |||
310 | struct nbr *nbr; | |||
311 | struct prune p; | |||
312 | struct iface *iface; | |||
313 | struct route_report *rr; | |||
314 | ssize_t n; | |||
315 | int shut = 0; | |||
316 | ||||
317 | if (event & EV_READ0x02) { | |||
| ||||
318 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
319 | fatal("imsg_read error"); | |||
320 | if (n == 0) /* connection closed */ | |||
321 | shut = 1; | |||
322 | } | |||
323 | if (event & EV_WRITE0x04) { | |||
324 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
325 | fatal("msgbuf_write"); | |||
326 | if (n == 0) /* connection closed */ | |||
327 | shut = 1; | |||
328 | } | |||
329 | ||||
330 | for (;;) { | |||
331 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
332 | fatal("dvmrpe_dispatch_rde: imsg_read error"); | |||
333 | if (n == 0) | |||
334 | break; | |||
335 | ||||
336 | switch (imsg.hdr.type) { | |||
337 | case IMSG_CTL_SHOW_RIB: | |||
338 | case IMSG_CTL_SHOW_SUM: | |||
339 | case IMSG_CTL_SHOW_MFC: | |||
340 | case IMSG_CTL_END: | |||
341 | control_imsg_relay(&imsg); | |||
342 | break; | |||
343 | case IMSG_FULL_ROUTE_REPORT: | |||
344 | /* add route reports to list */ | |||
345 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(*rr)) | |||
346 | fatalx("invalid size of RDE request"); | |||
347 | ||||
348 | if ((rr = calloc(1, sizeof(*rr))) == NULL((void *)0)) | |||
349 | fatal("dvmrpe_dispatch_rde"); | |||
350 | ||||
351 | memcpy(rr, imsg.data, sizeof(*rr)); | |||
352 | ||||
353 | /* general update, per interface */ | |||
354 | if (imsg.hdr.peerid == 0) { | |||
355 | /* add to interface list */ | |||
356 | LIST_FOREACH(iface, &deconf->iface_list,for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
357 | entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
358 | if (!if_nbr_list_empty(iface)) | |||
359 | rr_list_add(&iface->rr_list, | |||
360 | rr); | |||
361 | } | |||
362 | break; | |||
363 | } | |||
364 | ||||
365 | /* add to neighbor list */ | |||
366 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |||
367 | rr_list_add(&nbr->rr_list, rr); | |||
368 | break; | |||
369 | case IMSG_FULL_ROUTE_REPORT_END: | |||
370 | /* transmit route report */ | |||
371 | if (imsg.hdr.peerid == 0) { | |||
372 | /* | |||
373 | * send general route report on all | |||
374 | * interfaces with neighbors. | |||
375 | */ | |||
376 | LIST_FOREACH(iface, &deconf->iface_list,for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
377 | entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
378 | rr_list_send(&iface->rr_list, | |||
379 | iface, NULL((void *)0)); | |||
380 | } | |||
381 | break; | |||
382 | } | |||
383 | ||||
384 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |||
385 | rr_list_send(&nbr->rr_list, NULL((void *)0), nbr); | |||
386 | break; | |||
387 | case IMSG_SEND_PRUNE: | |||
388 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(p)) | |||
389 | fatalx("invalid size of RDE request"); | |||
390 | ||||
391 | memcpy(&p, imsg.data, sizeof(p)); | |||
392 | ||||
393 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
394 | if (p.ifindex == iface->ifindex) | |||
395 | break; | |||
396 | ||||
397 | if (iface == NULL((void *)0)) | |||
398 | fatalx("invalid interface in mfc"); | |||
399 | ||||
400 | nbr = nbr_find_ip(iface, p.nexthop.s_addr); | |||
401 | if (nbr == NULL((void *)0)) | |||
402 | fatalx("unknown neighbor to send prune"); | |||
403 | ||||
404 | send_prune(nbr, &p); | |||
405 | ||||
406 | break; | |||
407 | case IMSG_FLASH_UPDATE: | |||
408 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(*rr)) | |||
409 | fatalx("invalid size of RDE request"); | |||
410 | ||||
411 | if ((rr = calloc(1, sizeof(*rr))) == NULL((void *)0)) | |||
412 | fatal("dvmrpe_dispatch_rde"); | |||
413 | ||||
414 | memcpy(rr, imsg.data, sizeof(*rr)); | |||
415 | ||||
416 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
417 | if (!if_nbr_list_empty(iface)) { | |||
418 | rr_list_add(&iface->rr_list, rr); | |||
419 | rr_list_send(&iface->rr_list, iface, | |||
420 | NULL((void *)0)); | |||
421 | } | |||
422 | } | |||
423 | break; | |||
424 | case IMSG_FLASH_UPDATE_DS: | |||
425 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(*rr)) | |||
426 | fatalx("invalid size of RDE request"); | |||
427 | ||||
428 | if ((rr = calloc(1, sizeof(*rr))) == NULL((void *)0)) | |||
429 | fatal("dvmrpe_dispatch_rde"); | |||
430 | ||||
431 | memcpy(rr, imsg.data, sizeof(*rr)); | |||
432 | ||||
433 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) { | |||
434 | if (iface->ifindex == rr->ifindex) | |||
435 | continue; | |||
436 | if (!if_nbr_list_empty(iface)) { | |||
437 | rr_list_add(&iface->rr_list, rr); | |||
438 | rr_list_send(&iface->rr_list, iface, | |||
439 | NULL((void *)0)); | |||
440 | } | |||
441 | } | |||
442 | break; | |||
443 | default: | |||
444 | log_debug("dvmrpe_dispatch_rde: error handling imsg %d", | |||
445 | imsg.hdr.type); | |||
446 | break; | |||
447 | } | |||
448 | imsg_free(&imsg); | |||
449 | } | |||
450 | if (!shut) | |||
| ||||
451 | imsg_event_add(iev); | |||
452 | else { | |||
453 | /* this pipe is dead, so remove the event handler */ | |||
454 | event_del(&iev->ev); | |||
455 | event_loopexit(NULL((void *)0)); | |||
456 | } | |||
457 | } | |||
458 | ||||
459 | void | |||
460 | dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx) | |||
461 | { | |||
462 | struct iface *iface; | |||
463 | struct ctl_iface *ictl; | |||
464 | ||||
465 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
466 | if (idx == 0 || idx == iface->ifindex) { | |||
467 | ictl = if_to_ctl(iface); | |||
468 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, | |||
469 | 0, 0, -1, ictl, sizeof(struct ctl_iface)); | |||
470 | } | |||
471 | } | |||
472 | ||||
473 | void | |||
474 | dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx) | |||
475 | { | |||
476 | struct iface *iface; | |||
477 | struct ctl_iface *ictl; | |||
478 | ||||
479 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
480 | if (idx == 0 || idx == iface->ifindex) { | |||
481 | ictl = if_to_ctl(iface); | |||
482 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, | |||
483 | 0, 0, -1, ictl, sizeof(struct ctl_iface)); | |||
484 | group_list_dump(iface, c); | |||
485 | ||||
486 | } | |||
487 | } | |||
488 | ||||
489 | void | |||
490 | dvmrpe_nbr_ctl(struct ctl_conn *c) | |||
491 | { | |||
492 | struct iface *iface; | |||
493 | struct nbr *nbr; | |||
494 | struct ctl_nbr *nctl; | |||
495 | ||||
496 | LIST_FOREACH(iface, &deconf->iface_list, entry)for((iface) = ((&deconf->iface_list)->lh_first); (iface )!= ((void *)0); (iface) = ((iface)->entry.le_next)) | |||
497 | LIST_FOREACH(nbr, &iface->nbr_list, entry)for((nbr) = ((&iface->nbr_list)->lh_first); (nbr)!= ((void *)0); (nbr) = ((nbr)->entry.le_next)) { | |||
498 | nctl = nbr_to_ctl(nbr); | |||
499 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, | |||
500 | 0, 0, -1, nctl, sizeof(struct ctl_nbr)); | |||
501 | } | |||
502 | ||||
503 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL((void *)0), 0); | |||
504 | } |