xref: /src/tests/sys/netgraph/util.c (revision 5554abd9cc9702af30af90925b33c5efff4e7d88)
1a664ade9SLutz Donnerhacke /*-
224ea1dbfSLutz Donnerhacke  * SPDX-License-Identifier: BSD-3-Clause
324ea1dbfSLutz Donnerhacke  *
424ea1dbfSLutz Donnerhacke  * Copyright 2021 Lutz Donnerhacke
524ea1dbfSLutz Donnerhacke  *
624ea1dbfSLutz Donnerhacke  * Redistribution and use in source and binary forms, with or without
724ea1dbfSLutz Donnerhacke  * modification, are permitted provided that the following conditions
824ea1dbfSLutz Donnerhacke  * are met:
924ea1dbfSLutz Donnerhacke  *
1024ea1dbfSLutz Donnerhacke  * 1. Redistributions of source code must retain the above copyright
1124ea1dbfSLutz Donnerhacke  *    notice, this list of conditions and the following disclaimer.
1224ea1dbfSLutz Donnerhacke  * 2. Redistributions in binary form must reproduce the above
1324ea1dbfSLutz Donnerhacke  *    copyright notice, this list of conditions and the following
1424ea1dbfSLutz Donnerhacke  *    disclaimer in the documentation and/or other materials provided
1524ea1dbfSLutz Donnerhacke  *    with the distribution.
1624ea1dbfSLutz Donnerhacke  * 3. Neither the name of the copyright holder nor the names of its
1724ea1dbfSLutz Donnerhacke  *    contributors may be used to endorse or promote products derived
1824ea1dbfSLutz Donnerhacke  *    from this software without specific prior written permission.
1924ea1dbfSLutz Donnerhacke  *
2024ea1dbfSLutz Donnerhacke  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
2124ea1dbfSLutz Donnerhacke  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2224ea1dbfSLutz Donnerhacke  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2324ea1dbfSLutz Donnerhacke  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2424ea1dbfSLutz Donnerhacke  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
2524ea1dbfSLutz Donnerhacke  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2624ea1dbfSLutz Donnerhacke  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2724ea1dbfSLutz Donnerhacke  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2824ea1dbfSLutz Donnerhacke  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2924ea1dbfSLutz Donnerhacke  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3024ea1dbfSLutz Donnerhacke  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3124ea1dbfSLutz Donnerhacke  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3224ea1dbfSLutz Donnerhacke  * SUCH DAMAGE.
3324ea1dbfSLutz Donnerhacke  */
3424ea1dbfSLutz Donnerhacke #include <atf-c.h>
3524ea1dbfSLutz Donnerhacke #include <errno.h>
3624ea1dbfSLutz Donnerhacke #include <stdlib.h>
3724ea1dbfSLutz Donnerhacke #include <string.h>
3824ea1dbfSLutz Donnerhacke 
3924ea1dbfSLutz Donnerhacke #include <sys/select.h>
4024ea1dbfSLutz Donnerhacke #include <sys/queue.h>
4124ea1dbfSLutz Donnerhacke 
4224ea1dbfSLutz Donnerhacke #include "util.h"
4324ea1dbfSLutz Donnerhacke 
4424ea1dbfSLutz Donnerhacke 
4524ea1dbfSLutz Donnerhacke static int	cs = -1, ds = -1;
4624ea1dbfSLutz Donnerhacke static ng_error_t error_handling = FAIL;
4724ea1dbfSLutz Donnerhacke 
4824ea1dbfSLutz Donnerhacke #define CHECK(r, x)	do {			\
499021c466SLutz Donnerhacke 	if (!(x)) {				\
509021c466SLutz Donnerhacke 		if (error_handling == PASS)	\
5124ea1dbfSLutz Donnerhacke 		    return r;			\
529021c466SLutz Donnerhacke 		atf_tc_fail_requirement(file, line, "%s (%s)", \
539021c466SLutz Donnerhacke 		    #x " not met", strerror(errno));\
549021c466SLutz Donnerhacke 	}					\
5524ea1dbfSLutz Donnerhacke } while(0)
5624ea1dbfSLutz Donnerhacke 
57a664ade9SLutz Donnerhacke struct data_handler
58a664ade9SLutz Donnerhacke {
5924ea1dbfSLutz Donnerhacke 	char const     *hook;
6024ea1dbfSLutz Donnerhacke 	ng_data_handler_t handler;
6124ea1dbfSLutz Donnerhacke 			SLIST_ENTRY(data_handler) next;
6224ea1dbfSLutz Donnerhacke };
6324ea1dbfSLutz Donnerhacke static SLIST_HEAD(, data_handler) data_head = SLIST_HEAD_INITIALIZER(data_head);
6409307dbfSLutz Donnerhacke static ng_msg_handler_t msg_handler = NULL;
6524ea1dbfSLutz Donnerhacke 
6624ea1dbfSLutz Donnerhacke static void	handle_data(void *ctx);
6709307dbfSLutz Donnerhacke static void	handle_msg(void *ctx);
6824ea1dbfSLutz Donnerhacke 
6924ea1dbfSLutz Donnerhacke void
_ng_connect(char const * path1,char const * hook1,char const * path2,char const * hook2,char const * file,size_t line)709021c466SLutz Donnerhacke _ng_connect(char const *path1, char const *hook1,
719021c466SLutz Donnerhacke 	    char const *path2, char const *hook2,
729021c466SLutz Donnerhacke 	    char const *file, size_t line)
7324ea1dbfSLutz Donnerhacke {
7424ea1dbfSLutz Donnerhacke 	struct ngm_connect c;
7524ea1dbfSLutz Donnerhacke 
7624ea1dbfSLutz Donnerhacke 	strncpy(c.ourhook, hook1, sizeof(c.ourhook));
7724ea1dbfSLutz Donnerhacke 	strncpy(c.peerhook, hook2, sizeof(c.peerhook));
7824ea1dbfSLutz Donnerhacke 	strncpy(c.path, path2, sizeof(c.path));
7924ea1dbfSLutz Donnerhacke 
8024ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path1,
8124ea1dbfSLutz Donnerhacke 				NGM_GENERIC_COOKIE, NGM_CONNECT,
8224ea1dbfSLutz Donnerhacke 				&c, sizeof(c)));
8324ea1dbfSLutz Donnerhacke }
8424ea1dbfSLutz Donnerhacke 
8524ea1dbfSLutz Donnerhacke void
_ng_mkpeer(char const * path1,char const * hook1,char const * type,char const * hook2,char const * file,size_t line)869021c466SLutz Donnerhacke _ng_mkpeer(char const *path1, char const *hook1,
879021c466SLutz Donnerhacke 	   char const *type, char const *hook2,
889021c466SLutz Donnerhacke 	   char const *file, size_t line)
8924ea1dbfSLutz Donnerhacke {
9024ea1dbfSLutz Donnerhacke 	struct ngm_mkpeer p;
9124ea1dbfSLutz Donnerhacke 
9224ea1dbfSLutz Donnerhacke 	strncpy(p.ourhook, hook1, sizeof(p.ourhook));
9324ea1dbfSLutz Donnerhacke 	strncpy(p.peerhook, hook2, sizeof(p.peerhook));
9424ea1dbfSLutz Donnerhacke 	strncpy(p.type, type, sizeof(p.type));
9524ea1dbfSLutz Donnerhacke 
9624ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path1,
9724ea1dbfSLutz Donnerhacke 				NGM_GENERIC_COOKIE, NGM_MKPEER,
9824ea1dbfSLutz Donnerhacke 				&p, sizeof(p)));
9924ea1dbfSLutz Donnerhacke }
10024ea1dbfSLutz Donnerhacke 
10124ea1dbfSLutz Donnerhacke void
_ng_rmhook(char const * path,char const * hook,char const * file,size_t line)1029021c466SLutz Donnerhacke _ng_rmhook(char const *path, char const *hook,
1039021c466SLutz Donnerhacke 	   char const *file, size_t line)
10424ea1dbfSLutz Donnerhacke {
10524ea1dbfSLutz Donnerhacke 	struct ngm_rmhook h;
10624ea1dbfSLutz Donnerhacke 
10724ea1dbfSLutz Donnerhacke 	strncpy(h.ourhook, hook, sizeof(h.ourhook));
10824ea1dbfSLutz Donnerhacke 
10924ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
11024ea1dbfSLutz Donnerhacke 				NGM_GENERIC_COOKIE, NGM_RMHOOK,
11124ea1dbfSLutz Donnerhacke 				&h, sizeof(h)));
11224ea1dbfSLutz Donnerhacke }
11324ea1dbfSLutz Donnerhacke 
11424ea1dbfSLutz Donnerhacke void
_ng_name(char const * path,char const * name,char const * file,size_t line)1159021c466SLutz Donnerhacke _ng_name(char const *path, char const *name,
1169021c466SLutz Donnerhacke 	 char const *file, size_t line)
11724ea1dbfSLutz Donnerhacke {
11824ea1dbfSLutz Donnerhacke 	struct ngm_name	n;
11924ea1dbfSLutz Donnerhacke 
12024ea1dbfSLutz Donnerhacke 	strncpy(n.name, name, sizeof(n.name));
12124ea1dbfSLutz Donnerhacke 
12224ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
12324ea1dbfSLutz Donnerhacke 				NGM_GENERIC_COOKIE, NGM_NAME,
12424ea1dbfSLutz Donnerhacke 				&n, sizeof(n)));
12524ea1dbfSLutz Donnerhacke }
12624ea1dbfSLutz Donnerhacke 
12724ea1dbfSLutz Donnerhacke void
_ng_shutdown(char const * path,char const * file,size_t line)1289021c466SLutz Donnerhacke _ng_shutdown(char const *path,
1299021c466SLutz Donnerhacke 	     char const *file, size_t line)
13024ea1dbfSLutz Donnerhacke {
13124ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
13224ea1dbfSLutz Donnerhacke 				NGM_GENERIC_COOKIE, NGM_SHUTDOWN,
13324ea1dbfSLutz Donnerhacke 				NULL, 0));
13424ea1dbfSLutz Donnerhacke }
13524ea1dbfSLutz Donnerhacke 
13624ea1dbfSLutz Donnerhacke void
ng_register_data(char const * hook,ng_data_handler_t proc)13724ea1dbfSLutz Donnerhacke ng_register_data(char const *hook, ng_data_handler_t proc)
13824ea1dbfSLutz Donnerhacke {
13924ea1dbfSLutz Donnerhacke 	struct data_handler *p;
14024ea1dbfSLutz Donnerhacke 
14124ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p = calloc(1, sizeof(struct data_handler))));
14224ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p->hook = strdup(hook)));
14324ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p->handler = proc));
14424ea1dbfSLutz Donnerhacke 	SLIST_INSERT_HEAD(&data_head, p, next);
14524ea1dbfSLutz Donnerhacke }
14624ea1dbfSLutz Donnerhacke 
14724ea1dbfSLutz Donnerhacke void
_ng_send_data(char const * hook,void const * data,size_t len,char const * file,size_t line)1489021c466SLutz Donnerhacke _ng_send_data(char const *hook,
1499021c466SLutz Donnerhacke 	      void const *data, size_t len,
1509021c466SLutz Donnerhacke 	      char const *file, size_t line)
15124ea1dbfSLutz Donnerhacke {
15224ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendData(ds, hook, data, len));
15324ea1dbfSLutz Donnerhacke }
15424ea1dbfSLutz Donnerhacke 
15509307dbfSLutz Donnerhacke void
ng_register_msg(ng_msg_handler_t proc)156a664ade9SLutz Donnerhacke ng_register_msg(ng_msg_handler_t proc)
157a664ade9SLutz Donnerhacke {
15809307dbfSLutz Donnerhacke 	msg_handler = proc;
15909307dbfSLutz Donnerhacke }
16009307dbfSLutz Donnerhacke 
16124ea1dbfSLutz Donnerhacke static void
handle_msg(void * ctx)162a664ade9SLutz Donnerhacke handle_msg(void *ctx)
163a664ade9SLutz Donnerhacke {
16424ea1dbfSLutz Donnerhacke 	struct ng_mesg *m;
16524ea1dbfSLutz Donnerhacke 	char		path[NG_PATHSIZ];
16624ea1dbfSLutz Donnerhacke 
16724ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(-1 != NgAllocRecvMsg(cs, &m, path));
16824ea1dbfSLutz Donnerhacke 
16909307dbfSLutz Donnerhacke 	if (msg_handler != NULL)
17009307dbfSLutz Donnerhacke 		(*msg_handler) (path, m, ctx);
17109307dbfSLutz Donnerhacke 
17224ea1dbfSLutz Donnerhacke 	free(m);
17324ea1dbfSLutz Donnerhacke }
17424ea1dbfSLutz Donnerhacke 
17524ea1dbfSLutz Donnerhacke static void
handle_data(void * ctx)176a664ade9SLutz Donnerhacke handle_data(void *ctx)
177a664ade9SLutz Donnerhacke {
17824ea1dbfSLutz Donnerhacke 	char		hook[NG_HOOKSIZ];
17924ea1dbfSLutz Donnerhacke 	struct data_handler *hnd;
18024ea1dbfSLutz Donnerhacke 	u_char	       *data;
18124ea1dbfSLutz Donnerhacke 	int		len;
18224ea1dbfSLutz Donnerhacke 
18324ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(0 < (len = NgAllocRecvData(ds, &data, hook)));
18424ea1dbfSLutz Donnerhacke 	SLIST_FOREACH(hnd, &data_head, next)
185a664ade9SLutz Donnerhacke 	{
18624ea1dbfSLutz Donnerhacke 		if (0 == strcmp(hnd->hook, hook))
18724ea1dbfSLutz Donnerhacke 			break;
188a664ade9SLutz Donnerhacke 	}
18924ea1dbfSLutz Donnerhacke 
19024ea1dbfSLutz Donnerhacke 	if (hnd != NULL)
19124ea1dbfSLutz Donnerhacke 		(*(hnd->handler)) (data, len, ctx);
19224ea1dbfSLutz Donnerhacke 
19324ea1dbfSLutz Donnerhacke 	free(data);
19424ea1dbfSLutz Donnerhacke }
19524ea1dbfSLutz Donnerhacke 
19624ea1dbfSLutz Donnerhacke int
ng_handle_event(unsigned int ms,void * context)19724ea1dbfSLutz Donnerhacke ng_handle_event(unsigned int ms, void *context)
19824ea1dbfSLutz Donnerhacke {
19924ea1dbfSLutz Donnerhacke 	fd_set		fds;
20024ea1dbfSLutz Donnerhacke 	int		maxfd = (ds < cs) ? cs : ds;
20124ea1dbfSLutz Donnerhacke 	struct timeval	timeout = {0, ms * 1000lu};
20224ea1dbfSLutz Donnerhacke 
20324ea1dbfSLutz Donnerhacke 	FD_ZERO(&fds);
20424ea1dbfSLutz Donnerhacke 	FD_SET(cs, &fds);
20524ea1dbfSLutz Donnerhacke 	FD_SET(ds, &fds);
20624ea1dbfSLutz Donnerhacke retry:
207a664ade9SLutz Donnerhacke 	switch (select(maxfd + 1, &fds, NULL, NULL, &timeout))
208a664ade9SLutz Donnerhacke 	{
20924ea1dbfSLutz Donnerhacke 	case -1:
21024ea1dbfSLutz Donnerhacke 		ATF_REQUIRE_ERRNO(EINTR, 1);
21124ea1dbfSLutz Donnerhacke 		goto retry;
21224ea1dbfSLutz Donnerhacke 	case 0:			/* timeout */
21324ea1dbfSLutz Donnerhacke 		return 0;
21424ea1dbfSLutz Donnerhacke 	default:		/* something to do */
21524ea1dbfSLutz Donnerhacke 		if (FD_ISSET(cs, &fds))
21609307dbfSLutz Donnerhacke 			handle_msg(context);
21724ea1dbfSLutz Donnerhacke 		if (FD_ISSET(ds, &fds))
21824ea1dbfSLutz Donnerhacke 			handle_data(context);
21924ea1dbfSLutz Donnerhacke 		return 1;
22024ea1dbfSLutz Donnerhacke 	}
22124ea1dbfSLutz Donnerhacke }
22224ea1dbfSLutz Donnerhacke 
22324ea1dbfSLutz Donnerhacke void
ng_handle_events(unsigned int ms,void * context)22424ea1dbfSLutz Donnerhacke ng_handle_events(unsigned int ms, void *context)
22524ea1dbfSLutz Donnerhacke {
22624ea1dbfSLutz Donnerhacke 	while (ng_handle_event(ms, context))
22724ea1dbfSLutz Donnerhacke 		;
22824ea1dbfSLutz Donnerhacke }
22924ea1dbfSLutz Donnerhacke 
23024ea1dbfSLutz Donnerhacke int
_ng_send_msg(char const * path,char const * msg,char const * file,size_t line)2319021c466SLutz Donnerhacke _ng_send_msg(char const *path, char const *msg,
2329021c466SLutz Donnerhacke 	     char const *file, size_t line)
23324ea1dbfSLutz Donnerhacke {
23424ea1dbfSLutz Donnerhacke 	int		res;
23524ea1dbfSLutz Donnerhacke 
23624ea1dbfSLutz Donnerhacke 	CHECK(-1, -1 != (res = NgSendAsciiMsg(cs, path, "%s", msg)));
23724ea1dbfSLutz Donnerhacke 	return (res);
23824ea1dbfSLutz Donnerhacke }
23924ea1dbfSLutz Donnerhacke 
24024ea1dbfSLutz Donnerhacke ng_error_t
ng_errors(ng_error_t n)24124ea1dbfSLutz Donnerhacke ng_errors(ng_error_t n)
24224ea1dbfSLutz Donnerhacke {
24324ea1dbfSLutz Donnerhacke 	ng_error_t	o = error_handling;
24424ea1dbfSLutz Donnerhacke 
24524ea1dbfSLutz Donnerhacke 	error_handling = n;
24624ea1dbfSLutz Donnerhacke 	return (o);
24724ea1dbfSLutz Donnerhacke }
24824ea1dbfSLutz Donnerhacke 
24924ea1dbfSLutz Donnerhacke void
_ng_init(char const * file,size_t line)250a664ade9SLutz Donnerhacke _ng_init(char const *file, size_t line)
251a664ade9SLutz Donnerhacke {
25224ea1dbfSLutz Donnerhacke 	if (cs >= 0)		/* prevent reinit */
25324ea1dbfSLutz Donnerhacke 		return;
25424ea1dbfSLutz Donnerhacke 
2559021c466SLutz Donnerhacke 	CHECK(, 0 == NgMkSockNode(NULL, &cs, &ds));
25624ea1dbfSLutz Donnerhacke 	NgSetDebug(3);
25724ea1dbfSLutz Donnerhacke }
2585554abd9SLutz Donnerhacke 
2595554abd9SLutz Donnerhacke #define GD(x) void				\
2605554abd9SLutz Donnerhacke get_data##x(void *data, size_t len, void *ctx) {\
2615554abd9SLutz Donnerhacke 	int	       *cnt = ctx;		\
2625554abd9SLutz Donnerhacke 						\
2635554abd9SLutz Donnerhacke 	(void)data;				\
2645554abd9SLutz Donnerhacke 	(void)len;				\
2655554abd9SLutz Donnerhacke 	cnt[x]++;				\
2665554abd9SLutz Donnerhacke }
2675554abd9SLutz Donnerhacke 
2685554abd9SLutz Donnerhacke GD(0)
2695554abd9SLutz Donnerhacke GD(1)
2705554abd9SLutz Donnerhacke GD(2)
2715554abd9SLutz Donnerhacke GD(3)
2725554abd9SLutz Donnerhacke GD(4)
2735554abd9SLutz Donnerhacke GD(5)
2745554abd9SLutz Donnerhacke GD(6)
2755554abd9SLutz Donnerhacke GD(7)
2765554abd9SLutz Donnerhacke GD(8)
2775554abd9SLutz Donnerhacke GD(9)
278