xref: /freebsd/sys/netgraph/ng_device.c (revision dc08ffec870569914f44bcf26aa838310e343764)
1a8353960SJulian Elischer /*
2a8353960SJulian Elischer  * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
3a8353960SJulian Elischer  *
4a8353960SJulian Elischer  * Redistribution and use in source and binary forms, with or without
5a8353960SJulian Elischer  * modification, are permitted provided that the following conditions
6a8353960SJulian Elischer  * are met:
7a8353960SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
8a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
9a8353960SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
10a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
11a8353960SJulian Elischer  *    documentation and/or other materials provided with the distribution.
12a8353960SJulian Elischer  * 3. The name of the author may not be used to endorse or promote products
13a8353960SJulian Elischer  *    derived from this software without specific prior written permission.
14a8353960SJulian Elischer  *
15a8353960SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16a8353960SJulian Elischer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17a8353960SJulian Elischer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18a8353960SJulian Elischer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19a8353960SJulian Elischer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20a8353960SJulian Elischer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21a8353960SJulian Elischer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22a8353960SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a8353960SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24a8353960SJulian Elischer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a8353960SJulian Elischer  *
26a8353960SJulian Elischer  * Netgraph "device" node
27a8353960SJulian Elischer  *
28a8353960SJulian Elischer  * This node presents a /dev/ngd%d device that interfaces to an other
29a8353960SJulian Elischer  * netgraph node.
30a8353960SJulian Elischer  *
31a8353960SJulian Elischer  * $FreeBSD$
32a8353960SJulian Elischer  *
33a8353960SJulian Elischer  */
34a8353960SJulian Elischer 
35a8353960SJulian Elischer #include <sys/param.h>
36a8353960SJulian Elischer #include <sys/systm.h>
37a8353960SJulian Elischer #include <sys/kernel.h>
38a8353960SJulian Elischer #include <sys/mbuf.h>
39a8353960SJulian Elischer #include <sys/uio.h>
40a8353960SJulian Elischer #include <sys/queue.h>
41a8353960SJulian Elischer #include <sys/malloc.h>
42a8353960SJulian Elischer #include <sys/conf.h>
43a8353960SJulian Elischer #include <sys/poll.h>
44a8353960SJulian Elischer #include <sys/ioccom.h>
45a8353960SJulian Elischer 
46a8353960SJulian Elischer #include <netgraph/ng_message.h>
47a8353960SJulian Elischer #include <netgraph/netgraph.h>
48a8353960SJulian Elischer 
49a8353960SJulian Elischer #include "ng_device.h"
50a8353960SJulian Elischer 
51a8353960SJulian Elischer /* turn this on for verbose messages */
52a8353960SJulian Elischer #define NGD_DEBUG
53a8353960SJulian Elischer 
54a8353960SJulian Elischer /* Netgraph methods */
55a8353960SJulian Elischer static ng_constructor_t	ng_device_cons;
56a8353960SJulian Elischer static ng_rcvmsg_t	ng_device_rcvmsg;
57a8353960SJulian Elischer static ng_newhook_t	ng_device_newhook;
58a8353960SJulian Elischer static ng_connect_t 	ng_device_connect;
59a8353960SJulian Elischer static ng_rcvdata_t	ng_device_rcvdata;
60a8353960SJulian Elischer static ng_disconnect_t	ng_device_disconnect;
61a8353960SJulian Elischer static int              ng_device_mod_event(module_t mod, int event, void *data);
62a8353960SJulian Elischer 
63a8353960SJulian Elischer static int ng_device_init(void);
64a8353960SJulian Elischer static int get_free_unit(void);
65a8353960SJulian Elischer 
66a8353960SJulian Elischer /* Netgraph type */
67a8353960SJulian Elischer static struct ng_type typestruct = {
68a8353960SJulian Elischer 	NG_ABI_VERSION,			/* version */
69a8353960SJulian Elischer 	NG_DEVICE_NODE_TYPE,		/* name */
70a8353960SJulian Elischer 	ng_device_mod_event,		/* modevent */
71a8353960SJulian Elischer 	ng_device_cons, 		/* constructor */
72a8353960SJulian Elischer 	ng_device_rcvmsg, 		/* receive msg */
73a8353960SJulian Elischer 	NULL, 				/* shutdown */
74a8353960SJulian Elischer 	ng_device_newhook, 		/* newhook */
75a8353960SJulian Elischer 	NULL,				/* findhook */
76a8353960SJulian Elischer 	ng_device_connect, 		/* connect */
77a8353960SJulian Elischer 	ng_device_rcvdata, 		/* receive data */
78a8353960SJulian Elischer 	ng_device_disconnect, 		/* disconnect */
79a8353960SJulian Elischer 	NULL
80a8353960SJulian Elischer };
81a8353960SJulian Elischer NETGRAPH_INIT(device, &typestruct);
82a8353960SJulian Elischer 
83a8353960SJulian Elischer /* per hook data */
84a8353960SJulian Elischer struct ngd_connection {
85a8353960SJulian Elischer 	SLIST_ENTRY(ngd_connection) links;
86a8353960SJulian Elischer 
87a8353960SJulian Elischer 	dev_t 	ngddev;
88a8353960SJulian Elischer 	struct 	ng_hook *active_hook;
89a8353960SJulian Elischer 	char	*readq;
90a8353960SJulian Elischer 	int 	loc;
91a8353960SJulian Elischer 	int 	unit;
92a8353960SJulian Elischer };
93a8353960SJulian Elischer 
94a8353960SJulian Elischer /* global data */
95a8353960SJulian Elischer struct ngd_softc {
96a8353960SJulian Elischer 	SLIST_HEAD(, ngd_connection) head;
97a8353960SJulian Elischer 
98a8353960SJulian Elischer 	node_p node;
9987e2c66aSHartmut Brandt 	char nodename[NG_NODESIZ];
100a8353960SJulian Elischer } ngd_softc;
101a8353960SJulian Elischer 
102a8353960SJulian Elischer /* the per connection receiving queue maximum */
103a8353960SJulian Elischer #define NGD_QUEUE_SIZE (1024*10)
104a8353960SJulian Elischer 
105a8353960SJulian Elischer /* Maximum number of NGD devices */
106a8353960SJulian Elischer #define MAX_NGD	25 		/* should be more than enough for now */
107a8353960SJulian Elischer 
108a8353960SJulian Elischer static d_close_t ngdclose;
109a8353960SJulian Elischer static d_open_t ngdopen;
110a8353960SJulian Elischer static d_read_t ngdread;
111a8353960SJulian Elischer static d_write_t ngdwrite;
112a8353960SJulian Elischer static d_ioctl_t ngdioctl;
113a8353960SJulian Elischer static d_poll_t ngdpoll;
114a8353960SJulian Elischer 
115a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = {
116dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
117dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1187ac40f5fSPoul-Henning Kamp 	.d_open =	ngdopen,
1197ac40f5fSPoul-Henning Kamp 	.d_close =	ngdclose,
1207ac40f5fSPoul-Henning Kamp 	.d_read =	ngdread,
1217ac40f5fSPoul-Henning Kamp 	.d_write =	ngdwrite,
1227ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ngdioctl,
1237ac40f5fSPoul-Henning Kamp 	.d_poll =	ngdpoll,
1247ac40f5fSPoul-Henning Kamp 	.d_name =	"ngd",
125a8353960SJulian Elischer };
126a8353960SJulian Elischer 
127a8353960SJulian Elischer /*
128a8353960SJulian Elischer  * this holds all the stuff that should be done at load time
129a8353960SJulian Elischer  */
130a8353960SJulian Elischer static int
131a8353960SJulian Elischer ng_device_mod_event(module_t mod, int event, void *data)
132a8353960SJulian Elischer {
133a8353960SJulian Elischer 	int error = 0;
134a8353960SJulian Elischer 
135a8353960SJulian Elischer #ifdef NGD_DEBUG
136a8353960SJulian Elischer 	printf("%s()\n",__func__);
137a8353960SJulian Elischer #endif /* NGD_DEBUG */
138a8353960SJulian Elischer 
139a8353960SJulian Elischer 	switch (event) {
140a8353960SJulian Elischer 		case MOD_LOAD:
141a8353960SJulian Elischer 
142a8353960SJulian Elischer 			ng_device_init();
143a8353960SJulian Elischer 			break;
144a8353960SJulian Elischer 
145a8353960SJulian Elischer 		case MOD_UNLOAD:
146a8353960SJulian Elischer 			/* XXX do we need to do something specific ? */
147a8353960SJulian Elischer 			/* ng_device_breakdown */
148a8353960SJulian Elischer 			break;
149a8353960SJulian Elischer 
150a8353960SJulian Elischer 		default:
151a8353960SJulian Elischer 			error = EOPNOTSUPP;
152a8353960SJulian Elischer 			break;
153a8353960SJulian Elischer 	}
154a8353960SJulian Elischer 
155a8353960SJulian Elischer 	return(error);
156a8353960SJulian Elischer }
157a8353960SJulian Elischer 
158a8353960SJulian Elischer 
159a8353960SJulian Elischer static int
160a8353960SJulian Elischer ng_device_init()
161a8353960SJulian Elischer {
162a8353960SJulian Elischer         struct ngd_softc *sc = &ngd_softc;
163a8353960SJulian Elischer 
164a8353960SJulian Elischer #ifdef NGD_DEBUG
165a8353960SJulian Elischer 	printf("%s()\n",__func__);
166a8353960SJulian Elischer #endif /* NGD_DEBUG */
167a8353960SJulian Elischer 
168a8353960SJulian Elischer 	SLIST_INIT(&sc->head);
169a8353960SJulian Elischer 
170a8353960SJulian Elischer         if (ng_make_node_common(&typestruct, &sc->node) != 0) {
171a8353960SJulian Elischer                 printf("%s(): ng_make_node_common failed\n",__func__);
172a8353960SJulian Elischer                 return(ENXIO);
173a8353960SJulian Elischer         }
174a8353960SJulian Elischer         sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE);
175a8353960SJulian Elischer         if (ng_name_node(sc->node, sc->nodename)) {
176a8353960SJulian Elischer                 NG_NODE_UNREF(sc->node); /* make it go away again */
177a8353960SJulian Elischer                 printf("%s(): ng_name_node failed\n",__func__);
178a8353960SJulian Elischer                 return(ENXIO);
179a8353960SJulian Elischer         }
180a8353960SJulian Elischer         NG_NODE_SET_PRIVATE(sc->node, sc);
181a8353960SJulian Elischer 
182a8353960SJulian Elischer 	return(0);
183a8353960SJulian Elischer }
184a8353960SJulian Elischer 
185a8353960SJulian Elischer /*
186a8353960SJulian Elischer  * don't allow to be created, only the device can do that
187a8353960SJulian Elischer  */
188a8353960SJulian Elischer static int
189a8353960SJulian Elischer ng_device_cons(node_p node)
190a8353960SJulian Elischer {
191a8353960SJulian Elischer 
192a8353960SJulian Elischer #ifdef NGD_DEBUG
193a8353960SJulian Elischer 	printf("%s()\n",__func__);
194a8353960SJulian Elischer #endif /* NGD_DEBUG */
195a8353960SJulian Elischer 
196a8353960SJulian Elischer 	return(EINVAL);
197a8353960SJulian Elischer }
198a8353960SJulian Elischer 
199a8353960SJulian Elischer /*
200a8353960SJulian Elischer  * Receive control message. We just bounce it back as a reply.
201a8353960SJulian Elischer  */
202a8353960SJulian Elischer static int
203a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
204a8353960SJulian Elischer {
205a8353960SJulian Elischer         struct ngd_softc *sc = &ngd_softc;
206a8353960SJulian Elischer 	struct ng_mesg *msg;
207a8353960SJulian Elischer 	int error = 0;
208a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
209a8353960SJulian Elischer 	struct ngd_connection *tmp = NULL;
210a8353960SJulian Elischer 
211a8353960SJulian Elischer #ifdef NGD_DEBUG
212a8353960SJulian Elischer 	printf("%s()\n",__func__);
213a8353960SJulian Elischer #endif /* NGD_DEBUG */
214a8353960SJulian Elischer 
215a8353960SJulian Elischer 	NGI_GET_MSG(item, msg);
216a8353960SJulian Elischer 
217a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
218a8353960SJulian Elischer 		if(tmp->active_hook == lasthook) {
219a8353960SJulian Elischer 			connection = tmp;
220a8353960SJulian Elischer 		}
221a8353960SJulian Elischer 	}
222a8353960SJulian Elischer 	if(connection == NULL) {
223a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
224a8353960SJulian Elischer 		return(-1);
225a8353960SJulian Elischer 	}
226a8353960SJulian Elischer 
227a8353960SJulian Elischer 	return(error);
228a8353960SJulian Elischer }
229a8353960SJulian Elischer 
230a8353960SJulian Elischer static int
231a8353960SJulian Elischer get_free_unit()
232a8353960SJulian Elischer {
233a8353960SJulian Elischer 	struct ngd_connection *tmp = NULL;
234a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
235a8353960SJulian Elischer 	int n = 0;
236a8353960SJulian Elischer 	int unit = -1;
237a8353960SJulian Elischer 
238a8353960SJulian Elischer #ifdef NGD_DEBUG
239a8353960SJulian Elischer 	printf("%s()\n",__func__);
240a8353960SJulian Elischer #endif /* NGD_DEBUG */
241a8353960SJulian Elischer 
242a8353960SJulian Elischer 	/* When there is no list yet, the first device unit is always 0. */
243a8353960SJulian Elischer 	if SLIST_EMPTY(&sc->head) {
244a8353960SJulian Elischer 		unit = 0;
245a8353960SJulian Elischer 		return(unit);
246a8353960SJulian Elischer 	}
247a8353960SJulian Elischer 
248a8353960SJulian Elischer 	/* Just do a brute force loop to find the first free unit that is
249a8353960SJulian Elischer 	 * smaller than MAX_NGD.
250a8353960SJulian Elischer 	 * Set MAX_NGD to a large value, doesn't impact performance.
251a8353960SJulian Elischer 	 */
252a8353960SJulian Elischer 	for(n = 0;n<MAX_NGD && unit == -1;n++) {
253a8353960SJulian Elischer 		SLIST_FOREACH(tmp,&sc->head,links) {
254a8353960SJulian Elischer 
255a8353960SJulian Elischer 			if(tmp->unit == n) {
256a8353960SJulian Elischer 				unit = -1;
257a8353960SJulian Elischer 				break;
258a8353960SJulian Elischer 			}
259a8353960SJulian Elischer 			unit = n;
260a8353960SJulian Elischer 		}
261a8353960SJulian Elischer 	}
262a8353960SJulian Elischer 
263a8353960SJulian Elischer 	return(unit);
264a8353960SJulian Elischer }
265a8353960SJulian Elischer 
266a8353960SJulian Elischer /*
267a8353960SJulian Elischer  * incoming hook
268a8353960SJulian Elischer  */
269a8353960SJulian Elischer static int
270a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name)
271a8353960SJulian Elischer {
272a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
273a8353960SJulian Elischer 	struct ngd_connection * new_connection = NULL;
274a8353960SJulian Elischer 
275a8353960SJulian Elischer #ifdef NGD_DEBUG
276a8353960SJulian Elischer 	printf("%s()\n",__func__);
277a8353960SJulian Elischer #endif /* NGD_DEBUG */
278a8353960SJulian Elischer 
279a8353960SJulian Elischer 	new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT);
280a8353960SJulian Elischer 	if(new_connection == NULL) {
281a8353960SJulian Elischer 		printf("%s(): ERROR: new_connection == NULL\n",__func__);
282a8353960SJulian Elischer 		return(-1);
283a8353960SJulian Elischer 	}
284a8353960SJulian Elischer 
285a8353960SJulian Elischer 	new_connection->unit = get_free_unit();
286a8353960SJulian Elischer 	if(new_connection->unit<0) {
287a8353960SJulian Elischer 		printf("%s: No free unit found by get_free_unit(), "
288a8353960SJulian Elischer 				"increas MAX_NGD\n",__func__);
289a8353960SJulian Elischer 		return(-1);
290a8353960SJulian Elischer 	}
291a8353960SJulian Elischer 	new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit);
292a8353960SJulian Elischer 	if(new_connection->ngddev == NULL) {
293a8353960SJulian Elischer 		printf("%s(): make_dev failed\n",__func__);
294a8353960SJulian Elischer 		return(-1);
295a8353960SJulian Elischer 	}
296a8353960SJulian Elischer 
297a8353960SJulian Elischer 	new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
298a8353960SJulian Elischer 	if(new_connection->readq == NULL) {
299a8353960SJulian Elischer 		printf("%s(): readq malloc failed\n",__func__);
300a8353960SJulian Elischer 		return(-1);
301a8353960SJulian Elischer 	}
302a8353960SJulian Elischer 
303a8353960SJulian Elischer 	/* point to begin of buffer */
304a8353960SJulian Elischer 	new_connection->loc = 0;
305a8353960SJulian Elischer 	new_connection->active_hook = hook;
306a8353960SJulian Elischer 
307a8353960SJulian Elischer 	SLIST_INSERT_HEAD(&sc->head, new_connection, links);
308a8353960SJulian Elischer 
309a8353960SJulian Elischer 	return(0);
310a8353960SJulian Elischer }
311a8353960SJulian Elischer 
312a8353960SJulian Elischer /*
313a8353960SJulian Elischer  * we gave ok to a new hook
314a8353960SJulian Elischer  * now connect
315a8353960SJulian Elischer  */
316a8353960SJulian Elischer static int
317a8353960SJulian Elischer ng_device_connect(hook_p hook)
318a8353960SJulian Elischer {
319a8353960SJulian Elischer 
320a8353960SJulian Elischer #ifdef NGD_DEBUG
321a8353960SJulian Elischer 	printf("%s()\n",__func__);
322a8353960SJulian Elischer #endif /* NGD_DEBUG */
323a8353960SJulian Elischer 
324a8353960SJulian Elischer 	return(0);
325a8353960SJulian Elischer }
326a8353960SJulian Elischer 
327a8353960SJulian Elischer 
328a8353960SJulian Elischer /*
329a8353960SJulian Elischer  * Receive data from hook
330a8353960SJulian Elischer  */
331a8353960SJulian Elischer static int
332a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item)
333a8353960SJulian Elischer {
334a8353960SJulian Elischer 	struct mbuf *m;
335a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
336a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
337a8353960SJulian Elischer 	struct ngd_connection * tmp;
338a8353960SJulian Elischer 	char *buffer;
339a8353960SJulian Elischer 
340a8353960SJulian Elischer #ifdef NGD_DEBUG
341a8353960SJulian Elischer 	printf("%s()\n",__func__);
342a8353960SJulian Elischer #endif /* NGD_DEBUG */
343a8353960SJulian Elischer 
344a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
345a8353960SJulian Elischer 		if(tmp->active_hook == hook) {
346a8353960SJulian Elischer 			connection = tmp;
347a8353960SJulian Elischer 		}
348a8353960SJulian Elischer 	}
349a8353960SJulian Elischer 	if(connection == NULL) {
350a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
351a8353960SJulian Elischer 		return(-1);
352a8353960SJulian Elischer 	}
353a8353960SJulian Elischer 
354a8353960SJulian Elischer 	NGI_GET_M(item, m);
355a8353960SJulian Elischer 	NG_FREE_ITEM(item);
356a8353960SJulian Elischer 
357a8353960SJulian Elischer 	m = m_pullup(m,m->m_len);
358a8353960SJulian Elischer 	if(m == NULL) {
359a8353960SJulian Elischer 		printf("%s(): ERROR: m_pullup failed\n",__func__);
360a8353960SJulian Elischer 		return(-1);
361a8353960SJulian Elischer 	}
362a8353960SJulian Elischer 
363a8353960SJulian Elischer 	buffer = malloc(sizeof(char)*m->m_len, M_DEVBUF, M_NOWAIT | M_ZERO);
364a8353960SJulian Elischer 	if(buffer == NULL) {
365a8353960SJulian Elischer 		printf("%s(): ERROR: buffer malloc failed\n",__func__);
366a8353960SJulian Elischer 		return(-1);
367a8353960SJulian Elischer 	}
368a8353960SJulian Elischer 
369a8353960SJulian Elischer 	buffer = mtod(m,char *);
370a8353960SJulian Elischer 
371a8353960SJulian Elischer 	if( (connection->loc+m->m_len) < NGD_QUEUE_SIZE) {
372a8353960SJulian Elischer 	        memcpy(connection->readq+connection->loc, buffer, m->m_len);
373a8353960SJulian Elischer 		connection->loc += m->m_len;
374a8353960SJulian Elischer 	} else
375a8353960SJulian Elischer 		printf("%s(): queue full, first read out a bit\n",__func__);
376a8353960SJulian Elischer 
377a8353960SJulian Elischer 	free(buffer,M_DEVBUF);
378a8353960SJulian Elischer 
379a8353960SJulian Elischer 	return(0);
380a8353960SJulian Elischer }
381a8353960SJulian Elischer 
382a8353960SJulian Elischer /*
383a8353960SJulian Elischer  * Removal of the last link destroys the node
384a8353960SJulian Elischer  */
385a8353960SJulian Elischer static int
386a8353960SJulian Elischer ng_device_disconnect(hook_p hook)
387a8353960SJulian Elischer {
388a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
389a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
390a8353960SJulian Elischer 	struct ngd_connection * tmp;
391a8353960SJulian Elischer 
392a8353960SJulian Elischer #ifdef NGD_DEBUG
393a8353960SJulian Elischer 	printf("%s()\n",__func__);
394a8353960SJulian Elischer #endif /* NGD_DEBUG */
395a8353960SJulian Elischer 
396a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
397a8353960SJulian Elischer 		if(tmp->active_hook == hook) {
398a8353960SJulian Elischer 			connection = tmp;
399a8353960SJulian Elischer 		}
400a8353960SJulian Elischer 	}
401a8353960SJulian Elischer 	if(connection == NULL) {
402a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
403a8353960SJulian Elischer 		return(-1);
404a8353960SJulian Elischer 	}
405a8353960SJulian Elischer 
406a8353960SJulian Elischer         free(connection->readq,M_DEVBUF);
407a8353960SJulian Elischer 
408a8353960SJulian Elischer 	destroy_dev(connection->ngddev);
409a8353960SJulian Elischer 
410a8353960SJulian Elischer 	SLIST_REMOVE(&sc->head,connection,ngd_connection,links);
411a8353960SJulian Elischer 
412a8353960SJulian Elischer 	return(0);
413a8353960SJulian Elischer }
414a8353960SJulian Elischer /*
415a8353960SJulian Elischer  * the device is opened
416a8353960SJulian Elischer  */
417a8353960SJulian Elischer static int
418a8353960SJulian Elischer ngdopen(dev_t dev, int flag, int mode, struct thread *td)
419a8353960SJulian Elischer {
420a8353960SJulian Elischer 
421a8353960SJulian Elischer #ifdef NGD_DEBUG
422a8353960SJulian Elischer 	printf("%s()\n",__func__);
423a8353960SJulian Elischer #endif /* NGD_DEBUG */
424a8353960SJulian Elischer 
425a8353960SJulian Elischer 	return(0);
426a8353960SJulian Elischer }
427a8353960SJulian Elischer 
428a8353960SJulian Elischer /*
429a8353960SJulian Elischer  * the device is closed
430a8353960SJulian Elischer  */
431a8353960SJulian Elischer static int
432a8353960SJulian Elischer ngdclose(dev_t dev, int flag, int mode, struct thread *td)
433a8353960SJulian Elischer {
434a8353960SJulian Elischer 
435a8353960SJulian Elischer #ifdef NGD_DEBUG
436a8353960SJulian Elischer 	printf("%s()\n",__func__);
437a8353960SJulian Elischer #endif
438a8353960SJulian Elischer 
439a8353960SJulian Elischer 	return(0);
440a8353960SJulian Elischer }
441a8353960SJulian Elischer 
442a8353960SJulian Elischer 
443a8353960SJulian Elischer /*
444a8353960SJulian Elischer  * process ioctl
445a8353960SJulian Elischer  *
446a8353960SJulian Elischer  * they are translated into netgraph messages and passed on
447a8353960SJulian Elischer  *
448a8353960SJulian Elischer  */
449a8353960SJulian Elischer static int
450a8353960SJulian Elischer ngdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
451a8353960SJulian Elischer {
452a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
453a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
454a8353960SJulian Elischer 	struct ngd_connection * tmp;
455a8353960SJulian Elischer 	int error = 0;
456a8353960SJulian Elischer 	struct ng_mesg *msg;
457a8353960SJulian Elischer         struct ngd_param_s * datap;
458a8353960SJulian Elischer 
459a8353960SJulian Elischer #ifdef NGD_DEBUG
460a8353960SJulian Elischer 	printf("%s()\n",__func__);
461a8353960SJulian Elischer #endif /* NGD_DEBUG */
462a8353960SJulian Elischer 
463a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
464a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
465a8353960SJulian Elischer 			connection = tmp;
466a8353960SJulian Elischer 		}
467a8353960SJulian Elischer 	}
468a8353960SJulian Elischer 	if(connection == NULL) {
469a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
470a8353960SJulian Elischer 		return(-1);
471a8353960SJulian Elischer 	}
472a8353960SJulian Elischer 
473a8353960SJulian Elischer 	/* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */
474a8353960SJulian Elischer 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
475a8353960SJulian Elischer 			M_NOWAIT);
476a8353960SJulian Elischer 	if (msg == NULL) {
477a8353960SJulian Elischer 		printf("%s(): msg == NULL\n",__func__);
478a8353960SJulian Elischer 		goto nomsg;
479a8353960SJulian Elischer 	}
480a8353960SJulian Elischer 
481a8353960SJulian Elischer 	/* pass the ioctl data into the ->data area */
482a8353960SJulian Elischer 	datap = (struct ngd_param_s *)msg->data;
483a8353960SJulian Elischer         datap->p = addr;
484a8353960SJulian Elischer 
485a8353960SJulian Elischer 	/* NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr) */
486a8353960SJulian Elischer 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, NULL);
487a8353960SJulian Elischer 	if(error)
488a8353960SJulian Elischer 		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
489a8353960SJulian Elischer 
490a8353960SJulian Elischer nomsg:
491a8353960SJulian Elischer 
492a8353960SJulian Elischer 	return(0);
493a8353960SJulian Elischer }
494a8353960SJulian Elischer 
495a8353960SJulian Elischer 
496a8353960SJulian Elischer /*
497a8353960SJulian Elischer  * This function is called when a read(2) is done to our device.
498a8353960SJulian Elischer  * We pass the data available in kernelspace on into userland using
499a8353960SJulian Elischer  * uiomove.
500a8353960SJulian Elischer  */
501a8353960SJulian Elischer static int
502a8353960SJulian Elischer ngdread(dev_t dev, struct uio *uio, int flag)
503a8353960SJulian Elischer {
504a8353960SJulian Elischer 	int ret = 0, amnt;
505a8353960SJulian Elischer 	char buffer[uio->uio_resid+1];
506a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
507a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
508a8353960SJulian Elischer 	struct ngd_connection * tmp;
509a8353960SJulian Elischer 
510a8353960SJulian Elischer #ifdef NGD_DEBUG
511a8353960SJulian Elischer 	printf("%s()\n",__func__);
512a8353960SJulian Elischer #endif /* NGD_DEBUG */
513a8353960SJulian Elischer 
514a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
515a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
516a8353960SJulian Elischer 			connection = tmp;
517a8353960SJulian Elischer 		}
518a8353960SJulian Elischer 	}
519a8353960SJulian Elischer 	if(connection == NULL) {
520a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
521a8353960SJulian Elischer 		return(-1);
522a8353960SJulian Elischer 	}
523a8353960SJulian Elischer 
524a8353960SJulian Elischer 	while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) {
525a8353960SJulian Elischer 		amnt = MIN(uio->uio_resid,connection->loc);
526a8353960SJulian Elischer 
527a8353960SJulian Elischer 		memcpy(buffer,connection->readq, amnt);
528a8353960SJulian Elischer 		memcpy(connection->readq, connection->readq+amnt,
529a8353960SJulian Elischer 				connection->loc-amnt);
530a8353960SJulian Elischer 		connection->loc -= amnt;
531a8353960SJulian Elischer 
532a8353960SJulian Elischer 		ret = uiomove((caddr_t)buffer, amnt, uio);
533a8353960SJulian Elischer 		if(ret != 0)
534a8353960SJulian Elischer 			goto error;
535a8353960SJulian Elischer 
536a8353960SJulian Elischer 	}
537a8353960SJulian Elischer 	return(0);
538a8353960SJulian Elischer 
539a8353960SJulian Elischer error:
540a8353960SJulian Elischer 	printf("%s(): uiomove returns error %d\n",__func__,ret);
541a8353960SJulian Elischer 	/* do error cleanup here */
542a8353960SJulian Elischer 	return(ret);
543a8353960SJulian Elischer }
544a8353960SJulian Elischer 
545a8353960SJulian Elischer 
546a8353960SJulian Elischer /*
547a8353960SJulian Elischer  * This function is called when our device is written to.
548a8353960SJulian Elischer  * We read the data from userland into our local buffer and pass it on
549a8353960SJulian Elischer  * into the remote hook.
550a8353960SJulian Elischer  *
551a8353960SJulian Elischer  */
552a8353960SJulian Elischer static int
553a8353960SJulian Elischer ngdwrite(dev_t dev, struct uio *uio, int flag)
554a8353960SJulian Elischer {
555a8353960SJulian Elischer 	int ret;
556a8353960SJulian Elischer 	int error = 0;
557a8353960SJulian Elischer 	struct mbuf *m;
558a8353960SJulian Elischer 	char buffer[uio->uio_resid];
559a8353960SJulian Elischer 	int len = uio->uio_resid;
560a8353960SJulian Elischer 	struct ngd_softc *sc =& ngd_softc;
561a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
562a8353960SJulian Elischer 	struct ngd_connection * tmp;
563a8353960SJulian Elischer 
564a8353960SJulian Elischer #ifdef NGD_DEBUG
565a8353960SJulian Elischer 	printf("%s()\n",__func__);
566a8353960SJulian Elischer #endif /* NGD_DEBUG */
567a8353960SJulian Elischer 
568a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
569a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
570a8353960SJulian Elischer 			connection = tmp;
571a8353960SJulian Elischer 		}
572a8353960SJulian Elischer 	}
573a8353960SJulian Elischer 
574a8353960SJulian Elischer 	if(connection == NULL) {
575a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
576a8353960SJulian Elischer 		return(-1);
577a8353960SJulian Elischer 	}
578a8353960SJulian Elischer 
579a8353960SJulian Elischer 	if (len > 0) {
580a8353960SJulian Elischer 		if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0)
581a8353960SJulian Elischer 			goto error;
582a8353960SJulian Elischer 	} else
583a8353960SJulian Elischer 		printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__);
584a8353960SJulian Elischer 
585a8353960SJulian Elischer 	m = m_devget(buffer,len,0,NULL,NULL);
586a8353960SJulian Elischer 
587a8353960SJulian Elischer 	NG_SEND_DATA_ONLY(error,connection->active_hook,m);
588a8353960SJulian Elischer 
589a8353960SJulian Elischer 	return(0);
590a8353960SJulian Elischer 
591a8353960SJulian Elischer error:
592a8353960SJulian Elischer 	/* do error cleanup here */
593a8353960SJulian Elischer 	printf("%s(): uiomove returned err: %d\n",__func__,ret);
594a8353960SJulian Elischer 
595a8353960SJulian Elischer 	return(ret);
596a8353960SJulian Elischer }
597a8353960SJulian Elischer 
598a8353960SJulian Elischer /*
599a8353960SJulian Elischer  * we are being polled/selected
600a8353960SJulian Elischer  * check if there is data available for read
601a8353960SJulian Elischer  */
602a8353960SJulian Elischer static int
603a8353960SJulian Elischer ngdpoll(dev_t dev, int events, struct thread *td)
604a8353960SJulian Elischer {
605a8353960SJulian Elischer 	int revents = 0;
606a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
607a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
608a8353960SJulian Elischer 	struct ngd_connection * tmp;
609a8353960SJulian Elischer 
610a8353960SJulian Elischer 
611a8353960SJulian Elischer 	if (events & (POLLIN | POLLRDNORM)) {
612a8353960SJulian Elischer 		/* get the connection we have to know the loc from */
613a8353960SJulian Elischer 		SLIST_FOREACH(tmp,&sc->head,links) {
614a8353960SJulian Elischer 			if(tmp->ngddev == dev) {
615a8353960SJulian Elischer 				connection = tmp;
616a8353960SJulian Elischer 			}
617a8353960SJulian Elischer 		}
618a8353960SJulian Elischer 		if(connection == NULL) {
619a8353960SJulian Elischer 			printf("%s(): ERROR: connection is still NULL,"
620a8353960SJulian Elischer 				"no dev found\n",__func__);
621a8353960SJulian Elischer 			return(-1);
622a8353960SJulian Elischer 		}
623a8353960SJulian Elischer 
624a8353960SJulian Elischer 		if (connection->loc > 0)
625a8353960SJulian Elischer 			revents |= events & (POLLIN | POLLRDNORM);
626a8353960SJulian Elischer 	}
627a8353960SJulian Elischer 
628a8353960SJulian Elischer 	return(revents);
629a8353960SJulian Elischer }
630