1 /*
2  * $Id$
3  *
4  * Copyright (c) 2008, 2009
5  *      Sten Spans <sten@blinkenlights.nl>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "config.h"
21 #include <check.h>
22 
23 #include "common.h"
24 #include "util.h"
25 #include "proto/protos.h"
26 #include "main.h"
27 #include "parent.h"
28 #include "check_wrap.h"
29 
30 #ifdef USE_CAPABILITIES
31 #include <sys/prctl.h>
32 #include <sys/capability.h>
33 #endif
34 
35 #if HAVE_LINUX_ETHTOOL_H
36 #include <linux/ethtool.h>
37 #endif /* HAVE_LINUX_ETHTOOL_H */
38 #ifdef HAVE_NET_BPF_H
39 #include <net/bpf.h>
40 #endif /* HAVE_NET_BPF_H */
41 #ifdef HAVE_PCI_PCI_H
42 #include <pci/pci.h>
43 #endif /* HAVE_PCI_PCI_H */
44 
45 const char *ifname = NULL;
46 unsigned int ifindex = 0;
47 
48 uint32_t options = OPT_DAEMON | OPT_CHECK;
49 extern int dfd;
50 extern int mfd;
51 extern struct rfdhead rawfds;
52 
START_TEST(test_parent_init)53 START_TEST(test_parent_init) {
54     const char *errstr = NULL;
55     int spair[2], fd = -1;
56 
57     options |= OPT_DEBUG;
58 
59     // make sure stdout is not a tty
60     fd = dup(STDOUT_FILENO);
61     close(STDOUT_FILENO);
62     my_socketpair(spair);
63 
64     errstr = "test";
65     my_log(CRIT, errstr);
66     WRAP_FATAL_START();
67     parent_init(0, 0, 0);
68     WRAP_FATAL_END();
69     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
70 	"incorrect message logged: %s", check_wrap_errstr);
71 
72     close(spair[0]);
73     close(spair[1]);
74     fd = dup(fd);
75     options &= ~OPT_DEBUG;
76 }
77 END_TEST
78 
START_TEST(test_parent_signal)79 START_TEST(test_parent_signal) {
80     int sig = 0;
81     short event = 0;
82     pid_t pid = 1;
83     const char *errstr = NULL;
84 
85     loglevel = INFO;
86 
87     mark_point();
88     sig = SIGCHLD;
89     errstr = "quitting";
90     WRAP_FATAL_START();
91     parent_signal(sig, event, &pid);
92     WRAP_FATAL_END();
93     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
94 	"incorrect message logged: %s", check_wrap_errstr);
95 
96     mark_point();
97     check_wrap_fake |= FAKE_KILL;
98     sig = SIGINT;
99     errstr = "quitting";
100     WRAP_FATAL_START();
101     parent_signal(sig, event, &pid);
102     WRAP_FATAL_END();
103     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
104 	"incorrect message logged: %s", check_wrap_errstr);
105 
106     mark_point();
107     sig = SIGTERM;
108     errstr = "quitting";
109     WRAP_FATAL_START();
110     parent_signal(sig, event, &pid);
111     WRAP_FATAL_END();
112     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
113 	"incorrect message logged: %s", check_wrap_errstr);
114     check_wrap_fake &= ~FAKE_KILL;
115 
116     mark_point();
117     sig = SIGHUP;
118     errstr = "check";
119     my_log(CRIT, errstr);
120     parent_signal(sig, event, NULL);
121     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
122 	"incorrect message logged: %s", check_wrap_errstr);
123 
124     mark_point();
125     sig = 0;
126     errstr = "unexpected signal";
127     WRAP_FATAL_START();
128     parent_signal(sig, event, NULL);
129     WRAP_FATAL_END();
130     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
131 	"incorrect message logged: %s", check_wrap_errstr);
132 
133     // reset
134     check_wrap_fake = 0;
135 }
136 END_TEST
137 
START_TEST(test_parent_req)138 START_TEST(test_parent_req) {
139     struct parent_req mreq = {};
140     struct ether_hdr ether = {};
141     static uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
142     struct rawfd *rfd;
143     const char *errstr = NULL;
144     int spair[2], fd = -1;
145     short event = 0;
146 
147     loglevel = INFO;
148     my_socketpair(spair);
149 
150     // supply an invalid fd, resulting in a read error
151     mark_point();
152     errstr = "invalid request received";
153     my_log(CRIT, errstr);
154     WRAP_FATAL_START();
155     parent_req(fd, event);
156     WRAP_FATAL_END();
157     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
158 	"incorrect message logged: %s", check_wrap_errstr);
159 
160     // test a message with an incorrect size
161     mark_point();
162     errstr = "invalid request received";
163     WRAP_WRITE(spair[0], &mreq, 1);
164     WRAP_FATAL_START();
165     parent_req(spair[1], event);
166     WRAP_FATAL_END();
167     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
168 	"incorrect message logged: %s", check_wrap_errstr);
169 
170     // test a message with incorrect ifindex
171     mark_point();
172     mreq.op = PARENT_MAX - 1;
173     mreq.len = ETHER_MIN_LEN;
174 
175     errstr = "check";
176     my_log(CRIT, errstr);
177     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
178     WRAP_FATAL_START();
179     parent_req(spair[1], event);
180     WRAP_FATAL_END();
181     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
182 	"incorrect message logged: %s", check_wrap_errstr);
183 
184     // test a correct CLOSE
185     mark_point();
186     dfd = spair[1];
187     options |= OPT_DEBUG;
188     mreq.op = PARENT_CLOSE;
189     mreq.index = ifindex;
190     mreq.len = 0;
191     memcpy(ether.dst, lldp_dst, ETHER_ADDR_LEN);
192     ether.type = htons(ETHERTYPE_LLDP);
193     memcpy(mreq.buf, &ether, sizeof(struct ether_hdr));
194     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
195 
196     errstr = "check";
197     my_log(CRIT, errstr);
198     WRAP_FATAL_START();
199     parent_req(spair[1], event);
200     WRAP_FATAL_END();
201     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
202 	"incorrect message logged: %s", check_wrap_errstr);
203 
204     // test a correct CLOSE
205     mark_point();
206     fail_unless (rfd_byindex(&rawfds, ifindex) == NULL,
207     	"the queue should be empty");
208 
209     options |= OPT_DEBUG;
210     parent_open(ifindex, ifname);
211     fail_unless (rfd_byindex(&rawfds, ifindex) != NULL,
212     	"rfd should be added to the queue");
213 
214     errstr = "check";
215     my_log(CRIT, errstr);
216     mreq.op = PARENT_CLOSE;
217     mreq.index = ifindex;
218     strlcpy(mreq.name, ifname, IFNAMSIZ);
219     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
220     parent_req(spair[1], event);
221     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
222 	"incorrect message logged: %s", check_wrap_errstr);
223     fail_unless (rfd_byindex(&rawfds, ifindex) == NULL,
224     	"rfd should be removed from the queue");
225 
226 #if defined(SIOCSIFDESCR) || defined(HAVE_SYSFS)
227     // test a correct DESCR
228     mark_point();
229     mreq.op = PARENT_DESCR;
230     mreq.len = 1;
231 
232     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
233 
234     errstr = "check";
235     my_log(CRIT, errstr);
236     parent_req(spair[1], event);
237     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
238 	"incorrect message logged: %s", check_wrap_errstr);
239 #endif
240 
241 #ifdef HAVE_SYSFS
242     mark_point();
243     mreq.op = PARENT_ALIAS;
244     mreq.len = 1;
245 
246     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
247 
248     errstr = "check";
249     my_log(CRIT, errstr);
250     parent_req(spair[1], event);
251     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
252 	"incorrect message logged: %s", check_wrap_errstr);
253 
254     // test a correct DEVICE
255     mreq.op = PARENT_DEVICE;
256     mreq.len = 0;
257     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
258     parent_req(spair[1], event);
259     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
260 	"incorrect message logged: %s", check_wrap_errstr);
261 #endif /* HAVE_SYSFS */
262 
263     // test a failing return message
264     mark_point();
265     parent_open(ifindex, ifname);
266     rfd = rfd_byindex(&rawfds, ifindex);
267     fail_unless (rfd != NULL, "rfd should be added to the queue");
268     mreq.op = PARENT_CLOSE;
269     close(rfd->fd);
270     rfd->fd = dup(spair[1]);
271     WRAP_WRITE(spair[0], &mreq, PARENT_REQ_LEN(mreq.len));
272     close(spair[0]);
273 
274     errstr = "failed to return request to child";
275     WRAP_FATAL_START();
276     parent_req(spair[1], event);
277     WRAP_FATAL_END();
278     fail_unless (strcmp(check_wrap_errstr, errstr) == 0,
279 	"incorrect message logged: %s", check_wrap_errstr);
280     fail_unless (close(fd) == -1, "rfd->fd should be closed");
281     fail_unless (rfd_byindex(&rawfds, ifindex) == NULL,
282     	"rfd should be removed from the queue");
283 
284     close(spair[1]);
285 }
286 END_TEST
287 
START_TEST(test_parent_check)288 START_TEST(test_parent_check) {
289     struct parent_req mreq = {};
290 
291     mark_point();
292     mreq.op = PARENT_OPEN;
293     fail_unless(parent_check(&mreq) == EXIT_SUCCESS,
294 	"PARENT_OPEN check failed");
295 
296     mark_point();
297     mreq.op = PARENT_CLOSE;
298     fail_unless(parent_check(&mreq) == EXIT_SUCCESS,
299 	"PARENT_CLOSE check failed");
300 
301 #ifdef HAVE_LINUX_ETHTOOL_H
302     mark_point();
303     mreq.op = PARENT_ETHTOOL_GSET;
304     mreq.index = ifindex;
305     mreq.len = sizeof(struct ethtool_cmd);
306     fail_unless(parent_check(&mreq) == EXIT_SUCCESS,
307 	"PARENT_ETHTOOL_GSET check failed");
308 
309     mark_point();
310     mreq.op = PARENT_ETHTOOL_GDRV;
311     mreq.index = ifindex;
312     mreq.len = sizeof(struct ethtool_drvinfo);
313     fail_unless(parent_check(&mreq) == EXIT_SUCCESS,
314 	"PARENT_ETHTOOL_GDRV check failed");
315 #endif
316 
317 #ifdef SIOCSIFDESCR
318     mark_point();
319     mreq.op = PARENT_DESCR;
320     mreq.index = ifindex;
321     mreq.len = 0;
322     fail_unless(parent_check(&mreq) == EXIT_SUCCESS,
323 	"PARENT_DESCR check failed");
324 #endif
325 
326 #ifndef HAVE_LINUX_ETHTOOL_H
327     mark_point();
328     mreq.op = PARENT_ETHTOOL_GSET;
329     fail_unless(parent_check(&mreq) == EXIT_FAILURE,
330 	"parent_check should fail");
331 #endif
332 }
333 END_TEST
334 
START_TEST(test_parent_send)335 START_TEST(test_parent_send) {
336     struct rawfd *rfd;
337     struct parent_msg msg = {};
338     struct ether_hdr ether = {};
339     static uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
340     int spair[2];
341     const char *errstr;
342     short event = 0;
343 
344     loglevel = INFO;
345     options |= OPT_DEBUG;
346     my_socketpair(spair);
347     msg.index = ifindex;
348     msg.len = ETHER_MIN_LEN;
349     strlcpy(msg.name, ifname, IFNAMSIZ);
350 
351     dfd = spair[1];
352     parent_open(ifindex, ifname);
353     rfd = rfd_byindex(&rawfds, ifindex);
354     fail_unless (rfd != NULL, "rfd should be added to the queue");
355 
356     // incorrect msend msg.len should be skipped
357     mark_point();
358     errstr = "check";
359     my_log(CRIT, errstr);
360     WRAP_WRITE(spair[0], &msg, PARENT_MSG_LEN(msg.len) - 1);
361     WRAP_FATAL_START();
362     parent_send(spair[1], event);
363     WRAP_FATAL_END();
364     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
365 	"incorrect message logged: %s", check_wrap_errstr);
366 
367     // incorrect msend msg.index should fail
368     mark_point();
369     errstr = "invalid ifindex supplied";
370     msg.index = UINT32_MAX;
371     WRAP_WRITE(spair[0], &msg, PARENT_MSG_LEN(msg.len));
372     WRAP_FATAL_START();
373     parent_send(spair[1], event);
374     WRAP_FATAL_END();
375     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
376 	"incorrect message logged: %s", check_wrap_errstr);
377 
378     mark_point();
379     msg.index = ifindex;
380     msg.proto = PROTO_LLDP;
381     memcpy(ether.dst, lldp_dst, ETHER_ADDR_LEN);
382     ether.type = htons(ETHERTYPE_LLDP);
383     memcpy(msg.msg, &ether, sizeof(ether));
384     errstr = "only -1 bytes written";
385     close(rfd->fd);
386     rfd->fd = -1;
387     options &= ~OPT_DEBUG;
388     WRAP_WRITE(spair[0], &msg, PARENT_MSG_LEN(msg.len));
389     parent_send(spair[1], event);
390     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
391 	"incorrect message logged: %s", check_wrap_errstr);
392 
393     options |= OPT_DEBUG;
394 
395     close(spair[0]);
396     close(spair[1]);
397     rfd_closeall(&rawfds);
398 }
399 END_TEST
400 
START_TEST(test_parent_open_close)401 START_TEST(test_parent_open_close) {
402     struct rawfd *rfd;
403 
404     options |= OPT_DEBUG;
405     dfd = STDOUT_FILENO;
406 
407     mark_point();
408     parent_open(ifindex, ifname);
409     rfd = rfd_byindex(&rawfds, ifindex);
410     fail_unless (rfd != NULL,
411     	"rfd should be added to the queue");
412     parent_close(rfd);
413     fail_unless (rfd_byindex(&rawfds, ifindex) == NULL,
414     	"rfd should be removed from the queue");
415 
416     mark_point();
417     parent_open(ifindex, ifname);
418     rfd = rfd_byindex(&rawfds, ifindex);
419     fail_unless (rfd != NULL,
420     	"rfd should be added to the queue");
421 
422     parent_open(2, "lo1");
423     rfd = rfd_byindex(&rawfds, 2);
424     fail_unless (rfd != NULL,
425     	"rfd should be added to the queue");
426 
427     rfd_closeall(&rawfds);
428     fail_unless (TAILQ_EMPTY(&rawfds),
429     	"the queue should be empty");
430 }
431 END_TEST
432 
START_TEST(test_parent_socket)433 START_TEST(test_parent_socket) {
434     struct rawfd *rfd;
435     const char *errstr;
436 
437     options |= OPT_DEBUG;
438     dfd = STDOUT_FILENO;
439 
440     mark_point();
441     parent_open(ifindex, ifname);
442     rfd = rfd_byindex(&rawfds, ifindex);
443     fail_unless (rfd != NULL, "rfd should be added to the queue");
444 
445     mark_point();
446     // only run this as a regular user
447     if (!geteuid())
448 	return;
449 
450     options &= ~OPT_DEBUG;
451     errstr = "pcap_";
452     WRAP_FATAL_START();
453     parent_socket(rfd);
454     WRAP_FATAL_END();
455     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
456 	"incorrect message logged: %s", check_wrap_errstr);
457 
458     rfd = rfd_byindex(&rawfds, ifindex);
459     fail_unless (rfd != NULL,
460     	"rfd not found");
461     parent_close(rfd);
462     fail_unless (TAILQ_EMPTY(&rawfds),
463     	"the queue should be empty");
464 }
465 END_TEST
466 
START_TEST(test_parent_multi)467 START_TEST(test_parent_multi) {
468     struct rawfd rfd;
469     int spair[2];
470     const char *errstr;
471 
472     my_socketpair(spair);
473     rfd.fd = spair[1];
474     rfd.index = ifindex;
475     strlcpy(rfd.name, ifname, IFNAMSIZ);
476 
477     check_wrap_fake = 0;
478     protos[PROTO_LLDP].enabled = 1;
479 
480     mark_point();
481     options |= OPT_DEBUG;
482     errstr = "check";
483     my_log(CRIT, errstr);
484     parent_multi(&rfd, protos, 0);
485     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
486 	"incorrect message logged: %s", check_wrap_errstr);
487 
488     mark_point();
489     options &= ~OPT_DEBUG;
490     errstr = "unable to change LLDP multicast on";
491     WRAP_FATAL_START();
492     parent_multi(&rfd, protos, 1);
493     WRAP_FATAL_END();
494     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
495 	"incorrect message logged: %s", check_wrap_errstr);
496 
497     mark_point();
498     check_wrap_fake |= FAKE_IOCTL|FAKE_SETSOCKOPT;
499     errstr = "check";
500     my_log(CRIT, errstr);
501     parent_multi(&rfd, protos, 1);
502     check_wrap_fake = 0;
503     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
504 	"incorrect message logged: %s", check_wrap_errstr);
505 
506     // reset
507     check_wrap_fake = 0;
508     close(spair[0]);
509     close(spair[1]);
510 }
511 END_TEST
512 
START_TEST(test_parent_recv)513 START_TEST(test_parent_recv) {
514     struct rawfd *rfd;
515     short event = 0;
516     const char *errstr = NULL;
517     char *prefix, *suffix, *path = NULL;
518     char errbuf[PCAP_ERRBUF_SIZE];
519     int spair[2];
520 
521     my_socketpair(spair);
522 
523     options |= OPT_DEBUG;
524     loglevel = INFO;
525     dfd = STDOUT_FILENO;
526 
527     mark_point();
528     parent_open(ifindex, ifname);
529     rfd = rfd_byindex(&rawfds, ifindex);
530     fail_unless (rfd != NULL, "rfd should be added to the queue");
531 
532     if ((prefix = getenv("srcdir")) == NULL)
533         prefix = ".";
534 
535     mark_point();
536     suffix = "proto/broken/00.unknown";
537     fail_if(asprintf(&path, "%s/%s.pcap", prefix, suffix) == -1,
538             "asprintf failed");
539     fail_if((rfd->p_handle = pcap_open_offline(path, errbuf)) == NULL,
540         "failed to open %s: %s", path, errbuf);
541 
542     errstr = "unknown message type received";
543     my_log(CRIT, "test");
544     WRAP_FATAL_START();
545     parent_recv(rfd->fd, event, rfd);
546     WRAP_FATAL_END();
547     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
548 	"incorrect message logged: %s", check_wrap_errstr);
549 
550     pcap_close(rfd->p_handle);
551     rfd->p_handle = NULL;
552     free(path);
553 
554     mark_point();
555     suffix = "proto/broken/01.empty";
556     fail_if(asprintf(&path, "%s/%s.pcap", prefix, suffix) == -1,
557             "asprintf failed");
558     fail_if((rfd->p_handle = pcap_open_offline(path, errbuf)) == NULL,
559         "failed to open %s: %s", path, errbuf);
560 
561     errstr = "test";
562     my_log(CRIT, errstr);
563     WRAP_FATAL_START();
564     parent_recv(rfd->fd, event, rfd);
565     WRAP_FATAL_END();
566     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
567 	"incorrect message logged: %s", check_wrap_errstr);
568 
569     pcap_close(rfd->p_handle);
570     rfd->p_handle = NULL;
571     free(path);
572 
573     mark_point();
574     suffix = "proto/cdp/43.good.big";
575     fail_if(asprintf(&path, "%s/%s.pcap", prefix, suffix) == -1,
576             "asprintf failed");
577     fail_if((rfd->p_handle = pcap_open_offline(path, errbuf)) == NULL,
578         "failed to open %s: %s", path, errbuf);
579 
580     // closed child socket
581     mark_point();
582     errstr = "failed to send message to child";
583     my_log(CRIT, "test");
584     WRAP_FATAL_START();
585     parent_recv(rfd->fd, event, rfd);
586     WRAP_FATAL_END();
587     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
588 	"incorrect message logged: %s", check_wrap_errstr);
589     pcap_close(rfd->p_handle);
590     rfd->p_handle = NULL;
591 
592     // working
593     mark_point();
594     mfd = spair[0];
595 
596     fail_if((rfd->p_handle = pcap_open_offline(path, errbuf)) == NULL,
597         "failed to open %s: %s", path, errbuf);
598 
599     errstr = "received CDP message (422 bytes)";
600     my_log(CRIT, "test");
601     WRAP_FATAL_START();
602     parent_recv(rfd->fd, event, rfd);
603     WRAP_FATAL_END();
604     fail_unless (strncmp(check_wrap_errstr, errstr, strlen(errstr)) == 0,
605 	"incorrect message logged: %s", check_wrap_errstr);
606 
607     pcap_close(rfd->p_handle);
608     rfd->p_handle = NULL;
609     free(path);
610 
611     mark_point();
612     rfd_closeall(&rawfds);
613     close(spair[0]);
614     close(spair[1]);
615 }
616 END_TEST
617 
parent_suite(void)618 Suite * parent_suite (void) {
619     Suite *s = suite_create("parent.c");
620 
621     TAILQ_INIT(&rawfds);
622 
623     // parent test case
624     TCase *tc_parent = tcase_create("parent");
625     tcase_add_test(tc_parent, test_parent_init);
626     tcase_add_test(tc_parent, test_parent_signal);
627     tcase_add_test(tc_parent, test_parent_req);
628     tcase_add_test(tc_parent, test_parent_check);
629     tcase_add_test(tc_parent, test_parent_send);
630     tcase_add_test(tc_parent, test_parent_open_close);
631     tcase_add_test(tc_parent, test_parent_socket);
632     tcase_add_test(tc_parent, test_parent_multi);
633     tcase_add_test(tc_parent, test_parent_recv);
634     suite_add_tcase(s, tc_parent);
635 
636     ifname = "lo";
637     ifindex = if_nametoindex(ifname);
638     if (!ifindex) {
639 	ifname = "lo0";
640 	ifindex = if_nametoindex(ifname);
641     }
642 
643     return s;
644 }
645 
main(void)646 int main (void) {
647     int number_failed;
648     Suite *s = parent_suite ();
649     SRunner *sr = srunner_create (s);
650     srunner_run_all (sr, CK_NORMAL);
651     number_failed = srunner_ntests_failed (sr);
652     srunner_free (sr);
653     return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
654 }
655 
656