xref: /freebsd/tests/sys/netgraph/util.c (revision 24ea1dbf257aa6757f469bcd859f90e9ad851e59)
1*24ea1dbfSLutz Donnerhacke /*
2*24ea1dbfSLutz Donnerhacke  * SPDX-License-Identifier: BSD-3-Clause
3*24ea1dbfSLutz Donnerhacke  *
4*24ea1dbfSLutz Donnerhacke  * Copyright 2021 Lutz Donnerhacke
5*24ea1dbfSLutz Donnerhacke  *
6*24ea1dbfSLutz Donnerhacke  * Redistribution and use in source and binary forms, with or without
7*24ea1dbfSLutz Donnerhacke  * modification, are permitted provided that the following conditions
8*24ea1dbfSLutz Donnerhacke  * are met:
9*24ea1dbfSLutz Donnerhacke  *
10*24ea1dbfSLutz Donnerhacke  * 1. Redistributions of source code must retain the above copyright
11*24ea1dbfSLutz Donnerhacke  *    notice, this list of conditions and the following disclaimer.
12*24ea1dbfSLutz Donnerhacke  * 2. Redistributions in binary form must reproduce the above
13*24ea1dbfSLutz Donnerhacke  *    copyright notice, this list of conditions and the following
14*24ea1dbfSLutz Donnerhacke  *    disclaimer in the documentation and/or other materials provided
15*24ea1dbfSLutz Donnerhacke  *    with the distribution.
16*24ea1dbfSLutz Donnerhacke  * 3. Neither the name of the copyright holder nor the names of its
17*24ea1dbfSLutz Donnerhacke  *    contributors may be used to endorse or promote products derived
18*24ea1dbfSLutz Donnerhacke  *    from this software without specific prior written permission.
19*24ea1dbfSLutz Donnerhacke  *
20*24ea1dbfSLutz Donnerhacke  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21*24ea1dbfSLutz Donnerhacke  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22*24ea1dbfSLutz Donnerhacke  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23*24ea1dbfSLutz Donnerhacke  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24*24ea1dbfSLutz Donnerhacke  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25*24ea1dbfSLutz Donnerhacke  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26*24ea1dbfSLutz Donnerhacke  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27*24ea1dbfSLutz Donnerhacke  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*24ea1dbfSLutz Donnerhacke  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29*24ea1dbfSLutz Donnerhacke  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30*24ea1dbfSLutz Donnerhacke  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31*24ea1dbfSLutz Donnerhacke  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*24ea1dbfSLutz Donnerhacke  * SUCH DAMAGE.
33*24ea1dbfSLutz Donnerhacke  */
34*24ea1dbfSLutz Donnerhacke #include <atf-c.h>
35*24ea1dbfSLutz Donnerhacke #include <errno.h>
36*24ea1dbfSLutz Donnerhacke #include <stdlib.h>
37*24ea1dbfSLutz Donnerhacke #include <stdio.h>
38*24ea1dbfSLutz Donnerhacke #include <string.h>
39*24ea1dbfSLutz Donnerhacke 
40*24ea1dbfSLutz Donnerhacke #include <sys/select.h>
41*24ea1dbfSLutz Donnerhacke #include <sys/queue.h>
42*24ea1dbfSLutz Donnerhacke 
43*24ea1dbfSLutz Donnerhacke #include "util.h"
44*24ea1dbfSLutz Donnerhacke 
45*24ea1dbfSLutz Donnerhacke 
46*24ea1dbfSLutz Donnerhacke static int cs = -1, ds = -1;
47*24ea1dbfSLutz Donnerhacke static ng_error_t error_handling = FAIL;
48*24ea1dbfSLutz Donnerhacke 
49*24ea1dbfSLutz Donnerhacke #define CHECK(r, x)	do {		\
50*24ea1dbfSLutz Donnerhacke 	if (error_handling == FAIL)	\
51*24ea1dbfSLutz Donnerhacke 	    ATF_REQUIRE(x);		\
52*24ea1dbfSLutz Donnerhacke 	else if(!(x))			\
53*24ea1dbfSLutz Donnerhacke 	    return r;			\
54*24ea1dbfSLutz Donnerhacke } while(0)
55*24ea1dbfSLutz Donnerhacke 
56*24ea1dbfSLutz Donnerhacke struct data_handler {
57*24ea1dbfSLutz Donnerhacke 	char const *hook;
58*24ea1dbfSLutz Donnerhacke 	ng_data_handler_t handler;
59*24ea1dbfSLutz Donnerhacke 	SLIST_ENTRY(data_handler) next;
60*24ea1dbfSLutz Donnerhacke };
61*24ea1dbfSLutz Donnerhacke static SLIST_HEAD(, data_handler) data_head = SLIST_HEAD_INITIALIZER(data_head);
62*24ea1dbfSLutz Donnerhacke 
63*24ea1dbfSLutz Donnerhacke static void handle_data(void *ctx);
64*24ea1dbfSLutz Donnerhacke static void handle_msg(void);
65*24ea1dbfSLutz Donnerhacke 
66*24ea1dbfSLutz Donnerhacke void
67*24ea1dbfSLutz Donnerhacke ng_connect(char const *path1, char const *hook1,
68*24ea1dbfSLutz Donnerhacke 	   char const *path2, char const *hook2)
69*24ea1dbfSLutz Donnerhacke {
70*24ea1dbfSLutz Donnerhacke 	struct ngm_connect c;
71*24ea1dbfSLutz Donnerhacke 
72*24ea1dbfSLutz Donnerhacke 	strncpy(c.ourhook,  hook1, sizeof(c.ourhook));
73*24ea1dbfSLutz Donnerhacke 	strncpy(c.peerhook, hook2, sizeof(c.peerhook));
74*24ea1dbfSLutz Donnerhacke 	strncpy(c.path,     path2, sizeof(c.path));
75*24ea1dbfSLutz Donnerhacke 
76*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path1,
77*24ea1dbfSLutz Donnerhacke 	    NGM_GENERIC_COOKIE, NGM_CONNECT,
78*24ea1dbfSLutz Donnerhacke 	    &c, sizeof(c)));
79*24ea1dbfSLutz Donnerhacke }
80*24ea1dbfSLutz Donnerhacke 
81*24ea1dbfSLutz Donnerhacke void
82*24ea1dbfSLutz Donnerhacke ng_mkpeer(char const *path1, char const *hook1,
83*24ea1dbfSLutz Donnerhacke 	  char const *type,  char const *hook2)
84*24ea1dbfSLutz Donnerhacke {
85*24ea1dbfSLutz Donnerhacke 	struct ngm_mkpeer p;
86*24ea1dbfSLutz Donnerhacke 
87*24ea1dbfSLutz Donnerhacke 	strncpy(p.ourhook,  hook1, sizeof(p.ourhook));
88*24ea1dbfSLutz Donnerhacke 	strncpy(p.peerhook, hook2, sizeof(p.peerhook));
89*24ea1dbfSLutz Donnerhacke 	strncpy(p.type,     type,  sizeof(p.type));
90*24ea1dbfSLutz Donnerhacke 
91*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path1,
92*24ea1dbfSLutz Donnerhacke 	    NGM_GENERIC_COOKIE, NGM_MKPEER,
93*24ea1dbfSLutz Donnerhacke 	    &p, sizeof(p)));
94*24ea1dbfSLutz Donnerhacke }
95*24ea1dbfSLutz Donnerhacke 
96*24ea1dbfSLutz Donnerhacke void
97*24ea1dbfSLutz Donnerhacke ng_rmhook(char const *path, char const *hook)
98*24ea1dbfSLutz Donnerhacke {
99*24ea1dbfSLutz Donnerhacke 	struct ngm_rmhook h;
100*24ea1dbfSLutz Donnerhacke 
101*24ea1dbfSLutz Donnerhacke 	strncpy(h.ourhook, hook, sizeof(h.ourhook));
102*24ea1dbfSLutz Donnerhacke 
103*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
104*24ea1dbfSLutz Donnerhacke 	    NGM_GENERIC_COOKIE, NGM_RMHOOK,
105*24ea1dbfSLutz Donnerhacke 	    &h, sizeof(h)));
106*24ea1dbfSLutz Donnerhacke }
107*24ea1dbfSLutz Donnerhacke 
108*24ea1dbfSLutz Donnerhacke void
109*24ea1dbfSLutz Donnerhacke ng_name(char const *path, char const *name)
110*24ea1dbfSLutz Donnerhacke {
111*24ea1dbfSLutz Donnerhacke 	struct ngm_name n;
112*24ea1dbfSLutz Donnerhacke 
113*24ea1dbfSLutz Donnerhacke 	strncpy(n.name, name, sizeof(n.name));
114*24ea1dbfSLutz Donnerhacke 
115*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
116*24ea1dbfSLutz Donnerhacke 	    NGM_GENERIC_COOKIE, NGM_NAME,
117*24ea1dbfSLutz Donnerhacke 	    &n, sizeof(n)));
118*24ea1dbfSLutz Donnerhacke }
119*24ea1dbfSLutz Donnerhacke 
120*24ea1dbfSLutz Donnerhacke void
121*24ea1dbfSLutz Donnerhacke ng_shutdown(char const *path)
122*24ea1dbfSLutz Donnerhacke {
123*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendMsg(cs, path,
124*24ea1dbfSLutz Donnerhacke 	    NGM_GENERIC_COOKIE, NGM_SHUTDOWN,
125*24ea1dbfSLutz Donnerhacke 	    NULL, 0));
126*24ea1dbfSLutz Donnerhacke }
127*24ea1dbfSLutz Donnerhacke 
128*24ea1dbfSLutz Donnerhacke void
129*24ea1dbfSLutz Donnerhacke ng_register_data(char const *hook, ng_data_handler_t proc)
130*24ea1dbfSLutz Donnerhacke {
131*24ea1dbfSLutz Donnerhacke 	struct data_handler *p;
132*24ea1dbfSLutz Donnerhacke 
133*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p = calloc(1, sizeof(struct data_handler))));
134*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p->hook = strdup(hook)));
135*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(NULL != (p->handler = proc));
136*24ea1dbfSLutz Donnerhacke 	SLIST_INSERT_HEAD(&data_head, p, next);
137*24ea1dbfSLutz Donnerhacke }
138*24ea1dbfSLutz Donnerhacke 
139*24ea1dbfSLutz Donnerhacke void
140*24ea1dbfSLutz Donnerhacke ng_send_data(char const *hook,
141*24ea1dbfSLutz Donnerhacke 	     void const *data, size_t len)
142*24ea1dbfSLutz Donnerhacke {
143*24ea1dbfSLutz Donnerhacke 	CHECK(, -1 != NgSendData(ds, hook, data, len));
144*24ea1dbfSLutz Donnerhacke }
145*24ea1dbfSLutz Donnerhacke 
146*24ea1dbfSLutz Donnerhacke static void
147*24ea1dbfSLutz Donnerhacke handle_msg(void) {
148*24ea1dbfSLutz Donnerhacke 	struct ng_mesg *m;
149*24ea1dbfSLutz Donnerhacke 	char path[NG_PATHSIZ];
150*24ea1dbfSLutz Donnerhacke 
151*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(-1 != NgAllocRecvMsg(cs, &m, path));
152*24ea1dbfSLutz Donnerhacke 
153*24ea1dbfSLutz Donnerhacke 	printf("Got message from %s\n", path);
154*24ea1dbfSLutz Donnerhacke 	free(m);
155*24ea1dbfSLutz Donnerhacke }
156*24ea1dbfSLutz Donnerhacke 
157*24ea1dbfSLutz Donnerhacke static void
158*24ea1dbfSLutz Donnerhacke handle_data(void *ctx) {
159*24ea1dbfSLutz Donnerhacke 	char hook[NG_HOOKSIZ];
160*24ea1dbfSLutz Donnerhacke 	struct data_handler *hnd;
161*24ea1dbfSLutz Donnerhacke 	u_char *data;
162*24ea1dbfSLutz Donnerhacke 	int len;
163*24ea1dbfSLutz Donnerhacke 
164*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(0 < (len = NgAllocRecvData(ds, &data, hook)));
165*24ea1dbfSLutz Donnerhacke 	SLIST_FOREACH(hnd, &data_head, next)
166*24ea1dbfSLutz Donnerhacke 		if (0 == strcmp(hnd->hook, hook))
167*24ea1dbfSLutz Donnerhacke 			break;
168*24ea1dbfSLutz Donnerhacke 
169*24ea1dbfSLutz Donnerhacke 	if (hnd != NULL)
170*24ea1dbfSLutz Donnerhacke 		(*(hnd->handler))(data, len, ctx);
171*24ea1dbfSLutz Donnerhacke 
172*24ea1dbfSLutz Donnerhacke 	free(data);
173*24ea1dbfSLutz Donnerhacke }
174*24ea1dbfSLutz Donnerhacke 
175*24ea1dbfSLutz Donnerhacke int
176*24ea1dbfSLutz Donnerhacke ng_handle_event(unsigned int ms, void *context)
177*24ea1dbfSLutz Donnerhacke {
178*24ea1dbfSLutz Donnerhacke 	fd_set fds;
179*24ea1dbfSLutz Donnerhacke 	int maxfd = (ds < cs) ? cs : ds;
180*24ea1dbfSLutz Donnerhacke 	struct timeval timeout = { 0, ms * 1000lu };
181*24ea1dbfSLutz Donnerhacke 
182*24ea1dbfSLutz Donnerhacke 	FD_ZERO(&fds);
183*24ea1dbfSLutz Donnerhacke 	FD_SET(cs, &fds);
184*24ea1dbfSLutz Donnerhacke 	FD_SET(ds, &fds);
185*24ea1dbfSLutz Donnerhacke retry:
186*24ea1dbfSLutz Donnerhacke 	switch (select(maxfd+1, &fds, NULL, NULL, &timeout)) {
187*24ea1dbfSLutz Donnerhacke 	case -1:
188*24ea1dbfSLutz Donnerhacke 		ATF_REQUIRE_ERRNO(EINTR, 1);
189*24ea1dbfSLutz Donnerhacke 		goto retry;
190*24ea1dbfSLutz Donnerhacke 	case 0:			       /* timeout */
191*24ea1dbfSLutz Donnerhacke 		return 0;
192*24ea1dbfSLutz Donnerhacke 	default:		       /* something to do */
193*24ea1dbfSLutz Donnerhacke 		if (FD_ISSET(cs, &fds))
194*24ea1dbfSLutz Donnerhacke 		    handle_msg();
195*24ea1dbfSLutz Donnerhacke 		if (FD_ISSET(ds, &fds))
196*24ea1dbfSLutz Donnerhacke 		    handle_data(context);
197*24ea1dbfSLutz Donnerhacke 		return 1;
198*24ea1dbfSLutz Donnerhacke 	}
199*24ea1dbfSLutz Donnerhacke }
200*24ea1dbfSLutz Donnerhacke 
201*24ea1dbfSLutz Donnerhacke void
202*24ea1dbfSLutz Donnerhacke ng_handle_events(unsigned int ms, void *context)
203*24ea1dbfSLutz Donnerhacke {
204*24ea1dbfSLutz Donnerhacke 	while(ng_handle_event(ms, context))
205*24ea1dbfSLutz Donnerhacke 		;
206*24ea1dbfSLutz Donnerhacke }
207*24ea1dbfSLutz Donnerhacke 
208*24ea1dbfSLutz Donnerhacke int
209*24ea1dbfSLutz Donnerhacke ng_send_msg(char const *path, char const *msg)
210*24ea1dbfSLutz Donnerhacke {
211*24ea1dbfSLutz Donnerhacke 	int res;
212*24ea1dbfSLutz Donnerhacke 
213*24ea1dbfSLutz Donnerhacke 	CHECK(-1, -1 != (res = NgSendAsciiMsg(cs, path, "%s", msg)));
214*24ea1dbfSLutz Donnerhacke 	return (res);
215*24ea1dbfSLutz Donnerhacke }
216*24ea1dbfSLutz Donnerhacke 
217*24ea1dbfSLutz Donnerhacke ng_error_t
218*24ea1dbfSLutz Donnerhacke ng_errors(ng_error_t n)
219*24ea1dbfSLutz Donnerhacke {
220*24ea1dbfSLutz Donnerhacke 	ng_error_t o = error_handling;
221*24ea1dbfSLutz Donnerhacke 
222*24ea1dbfSLutz Donnerhacke 	error_handling = n;
223*24ea1dbfSLutz Donnerhacke 	return (o);
224*24ea1dbfSLutz Donnerhacke }
225*24ea1dbfSLutz Donnerhacke 
226*24ea1dbfSLutz Donnerhacke void
227*24ea1dbfSLutz Donnerhacke ng_init(void) {
228*24ea1dbfSLutz Donnerhacke 	if (cs >= 0)		       /* prevent reinit */
229*24ea1dbfSLutz Donnerhacke 		return;
230*24ea1dbfSLutz Donnerhacke 
231*24ea1dbfSLutz Donnerhacke 	ATF_REQUIRE(0 == NgMkSockNode(NULL, &cs, &ds));
232*24ea1dbfSLutz Donnerhacke 	NgSetDebug(3);
233*24ea1dbfSLutz Donnerhacke }
234