xref: /freebsd/sys/netgraph/ng_device.c (revision f8aae7776f85d2fa8aa93f73c37782cd9e1204c6)
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 = {
68f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
69f8aae777SJulian Elischer 	.name =		NG_DEVICE_NODE_TYPE,
70f8aae777SJulian Elischer 	.mod_event =	ng_device_mod_event,
71f8aae777SJulian Elischer 	.constructor =	ng_device_cons,
72f8aae777SJulian Elischer 	.rcvmsg =	ng_device_rcvmsg,
73f8aae777SJulian Elischer 	.newhook =	ng_device_newhook,
74f8aae777SJulian Elischer 	.connect = 	ng_device_connect,
75f8aae777SJulian Elischer 	.rcvdata =	ng_device_rcvdata,
76f8aae777SJulian Elischer 	.disconnect =	ng_device_disconnect,
77a8353960SJulian Elischer };
78a8353960SJulian Elischer NETGRAPH_INIT(device, &typestruct);
79a8353960SJulian Elischer 
80a8353960SJulian Elischer /* per hook data */
81a8353960SJulian Elischer struct ngd_connection {
82a8353960SJulian Elischer 	SLIST_ENTRY(ngd_connection) links;
83a8353960SJulian Elischer 
84a8353960SJulian Elischer 	dev_t 	ngddev;
85a8353960SJulian Elischer 	struct 	ng_hook *active_hook;
86a8353960SJulian Elischer 	char	*readq;
87a8353960SJulian Elischer 	int 	loc;
88a8353960SJulian Elischer 	int 	unit;
89a8353960SJulian Elischer };
90a8353960SJulian Elischer 
91a8353960SJulian Elischer /* global data */
92a8353960SJulian Elischer struct ngd_softc {
93a8353960SJulian Elischer 	SLIST_HEAD(, ngd_connection) head;
94a8353960SJulian Elischer 
95a8353960SJulian Elischer 	node_p node;
9687e2c66aSHartmut Brandt 	char nodename[NG_NODESIZ];
97a8353960SJulian Elischer } ngd_softc;
98a8353960SJulian Elischer 
99a8353960SJulian Elischer /* the per connection receiving queue maximum */
100a8353960SJulian Elischer #define NGD_QUEUE_SIZE (1024*10)
101a8353960SJulian Elischer 
102a8353960SJulian Elischer /* Maximum number of NGD devices */
103a8353960SJulian Elischer #define MAX_NGD	25 		/* should be more than enough for now */
104a8353960SJulian Elischer 
105a8353960SJulian Elischer static d_close_t ngdclose;
106a8353960SJulian Elischer static d_open_t ngdopen;
107a8353960SJulian Elischer static d_read_t ngdread;
108a8353960SJulian Elischer static d_write_t ngdwrite;
109a8353960SJulian Elischer static d_ioctl_t ngdioctl;
110a8353960SJulian Elischer static d_poll_t ngdpoll;
111a8353960SJulian Elischer 
112a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = {
113dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
114dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1157ac40f5fSPoul-Henning Kamp 	.d_open =	ngdopen,
1167ac40f5fSPoul-Henning Kamp 	.d_close =	ngdclose,
1177ac40f5fSPoul-Henning Kamp 	.d_read =	ngdread,
1187ac40f5fSPoul-Henning Kamp 	.d_write =	ngdwrite,
1197ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ngdioctl,
1207ac40f5fSPoul-Henning Kamp 	.d_poll =	ngdpoll,
1217ac40f5fSPoul-Henning Kamp 	.d_name =	"ngd",
122a8353960SJulian Elischer };
123a8353960SJulian Elischer 
124a8353960SJulian Elischer /*
125a8353960SJulian Elischer  * this holds all the stuff that should be done at load time
126a8353960SJulian Elischer  */
127a8353960SJulian Elischer static int
128a8353960SJulian Elischer ng_device_mod_event(module_t mod, int event, void *data)
129a8353960SJulian Elischer {
130a8353960SJulian Elischer 	int error = 0;
131a8353960SJulian Elischer 
132a8353960SJulian Elischer #ifdef NGD_DEBUG
133a8353960SJulian Elischer 	printf("%s()\n",__func__);
134a8353960SJulian Elischer #endif /* NGD_DEBUG */
135a8353960SJulian Elischer 
136a8353960SJulian Elischer 	switch (event) {
137a8353960SJulian Elischer 		case MOD_LOAD:
138a8353960SJulian Elischer 
139a8353960SJulian Elischer 			ng_device_init();
140a8353960SJulian Elischer 			break;
141a8353960SJulian Elischer 
142a8353960SJulian Elischer 		case MOD_UNLOAD:
143a8353960SJulian Elischer 			/* XXX do we need to do something specific ? */
144a8353960SJulian Elischer 			/* ng_device_breakdown */
145a8353960SJulian Elischer 			break;
146a8353960SJulian Elischer 
147a8353960SJulian Elischer 		default:
148a8353960SJulian Elischer 			error = EOPNOTSUPP;
149a8353960SJulian Elischer 			break;
150a8353960SJulian Elischer 	}
151a8353960SJulian Elischer 
152a8353960SJulian Elischer 	return(error);
153a8353960SJulian Elischer }
154a8353960SJulian Elischer 
155a8353960SJulian Elischer 
156a8353960SJulian Elischer static int
157a8353960SJulian Elischer ng_device_init()
158a8353960SJulian Elischer {
159a8353960SJulian Elischer         struct ngd_softc *sc = &ngd_softc;
160a8353960SJulian Elischer 
161a8353960SJulian Elischer #ifdef NGD_DEBUG
162a8353960SJulian Elischer 	printf("%s()\n",__func__);
163a8353960SJulian Elischer #endif /* NGD_DEBUG */
164a8353960SJulian Elischer 
165a8353960SJulian Elischer 	SLIST_INIT(&sc->head);
166a8353960SJulian Elischer 
167a8353960SJulian Elischer         if (ng_make_node_common(&typestruct, &sc->node) != 0) {
168a8353960SJulian Elischer                 printf("%s(): ng_make_node_common failed\n",__func__);
169a8353960SJulian Elischer                 return(ENXIO);
170a8353960SJulian Elischer         }
171a8353960SJulian Elischer         sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE);
172a8353960SJulian Elischer         if (ng_name_node(sc->node, sc->nodename)) {
173a8353960SJulian Elischer                 NG_NODE_UNREF(sc->node); /* make it go away again */
174a8353960SJulian Elischer                 printf("%s(): ng_name_node failed\n",__func__);
175a8353960SJulian Elischer                 return(ENXIO);
176a8353960SJulian Elischer         }
177a8353960SJulian Elischer         NG_NODE_SET_PRIVATE(sc->node, sc);
178a8353960SJulian Elischer 
179a8353960SJulian Elischer 	return(0);
180a8353960SJulian Elischer }
181a8353960SJulian Elischer 
182a8353960SJulian Elischer /*
183a8353960SJulian Elischer  * don't allow to be created, only the device can do that
184a8353960SJulian Elischer  */
185a8353960SJulian Elischer static int
186a8353960SJulian Elischer ng_device_cons(node_p node)
187a8353960SJulian Elischer {
188a8353960SJulian Elischer 
189a8353960SJulian Elischer #ifdef NGD_DEBUG
190a8353960SJulian Elischer 	printf("%s()\n",__func__);
191a8353960SJulian Elischer #endif /* NGD_DEBUG */
192a8353960SJulian Elischer 
193a8353960SJulian Elischer 	return(EINVAL);
194a8353960SJulian Elischer }
195a8353960SJulian Elischer 
196a8353960SJulian Elischer /*
197a8353960SJulian Elischer  * Receive control message. We just bounce it back as a reply.
198a8353960SJulian Elischer  */
199a8353960SJulian Elischer static int
200a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
201a8353960SJulian Elischer {
202a8353960SJulian Elischer         struct ngd_softc *sc = &ngd_softc;
203a8353960SJulian Elischer 	struct ng_mesg *msg;
204a8353960SJulian Elischer 	int error = 0;
205a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
206a8353960SJulian Elischer 	struct ngd_connection *tmp = NULL;
207a8353960SJulian Elischer 
208a8353960SJulian Elischer #ifdef NGD_DEBUG
209a8353960SJulian Elischer 	printf("%s()\n",__func__);
210a8353960SJulian Elischer #endif /* NGD_DEBUG */
211a8353960SJulian Elischer 
212a8353960SJulian Elischer 	NGI_GET_MSG(item, msg);
213a8353960SJulian Elischer 
214a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
215a8353960SJulian Elischer 		if(tmp->active_hook == lasthook) {
216a8353960SJulian Elischer 			connection = tmp;
217a8353960SJulian Elischer 		}
218a8353960SJulian Elischer 	}
219a8353960SJulian Elischer 	if(connection == NULL) {
220a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
221a8353960SJulian Elischer 		return(-1);
222a8353960SJulian Elischer 	}
223a8353960SJulian Elischer 
224a8353960SJulian Elischer 	return(error);
225a8353960SJulian Elischer }
226a8353960SJulian Elischer 
227a8353960SJulian Elischer static int
228a8353960SJulian Elischer get_free_unit()
229a8353960SJulian Elischer {
230a8353960SJulian Elischer 	struct ngd_connection *tmp = NULL;
231a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
232a8353960SJulian Elischer 	int n = 0;
233a8353960SJulian Elischer 	int unit = -1;
234a8353960SJulian Elischer 
235a8353960SJulian Elischer #ifdef NGD_DEBUG
236a8353960SJulian Elischer 	printf("%s()\n",__func__);
237a8353960SJulian Elischer #endif /* NGD_DEBUG */
238a8353960SJulian Elischer 
239a8353960SJulian Elischer 	/* When there is no list yet, the first device unit is always 0. */
240a8353960SJulian Elischer 	if SLIST_EMPTY(&sc->head) {
241a8353960SJulian Elischer 		unit = 0;
242a8353960SJulian Elischer 		return(unit);
243a8353960SJulian Elischer 	}
244a8353960SJulian Elischer 
245a8353960SJulian Elischer 	/* Just do a brute force loop to find the first free unit that is
246a8353960SJulian Elischer 	 * smaller than MAX_NGD.
247a8353960SJulian Elischer 	 * Set MAX_NGD to a large value, doesn't impact performance.
248a8353960SJulian Elischer 	 */
249a8353960SJulian Elischer 	for(n = 0;n<MAX_NGD && unit == -1;n++) {
250a8353960SJulian Elischer 		SLIST_FOREACH(tmp,&sc->head,links) {
251a8353960SJulian Elischer 
252a8353960SJulian Elischer 			if(tmp->unit == n) {
253a8353960SJulian Elischer 				unit = -1;
254a8353960SJulian Elischer 				break;
255a8353960SJulian Elischer 			}
256a8353960SJulian Elischer 			unit = n;
257a8353960SJulian Elischer 		}
258a8353960SJulian Elischer 	}
259a8353960SJulian Elischer 
260a8353960SJulian Elischer 	return(unit);
261a8353960SJulian Elischer }
262a8353960SJulian Elischer 
263a8353960SJulian Elischer /*
264a8353960SJulian Elischer  * incoming hook
265a8353960SJulian Elischer  */
266a8353960SJulian Elischer static int
267a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name)
268a8353960SJulian Elischer {
269a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
270a8353960SJulian Elischer 	struct ngd_connection * new_connection = NULL;
271a8353960SJulian Elischer 
272a8353960SJulian Elischer #ifdef NGD_DEBUG
273a8353960SJulian Elischer 	printf("%s()\n",__func__);
274a8353960SJulian Elischer #endif /* NGD_DEBUG */
275a8353960SJulian Elischer 
276a8353960SJulian Elischer 	new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT);
277a8353960SJulian Elischer 	if(new_connection == NULL) {
278a8353960SJulian Elischer 		printf("%s(): ERROR: new_connection == NULL\n",__func__);
279a8353960SJulian Elischer 		return(-1);
280a8353960SJulian Elischer 	}
281a8353960SJulian Elischer 
282a8353960SJulian Elischer 	new_connection->unit = get_free_unit();
283a8353960SJulian Elischer 	if(new_connection->unit<0) {
284a8353960SJulian Elischer 		printf("%s: No free unit found by get_free_unit(), "
285a8353960SJulian Elischer 				"increas MAX_NGD\n",__func__);
286a8353960SJulian Elischer 		return(-1);
287a8353960SJulian Elischer 	}
288a8353960SJulian Elischer 	new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit);
289a8353960SJulian Elischer 	if(new_connection->ngddev == NULL) {
290a8353960SJulian Elischer 		printf("%s(): make_dev failed\n",__func__);
291a8353960SJulian Elischer 		return(-1);
292a8353960SJulian Elischer 	}
293a8353960SJulian Elischer 
294a8353960SJulian Elischer 	new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
295a8353960SJulian Elischer 	if(new_connection->readq == NULL) {
296a8353960SJulian Elischer 		printf("%s(): readq malloc failed\n",__func__);
297a8353960SJulian Elischer 		return(-1);
298a8353960SJulian Elischer 	}
299a8353960SJulian Elischer 
300a8353960SJulian Elischer 	/* point to begin of buffer */
301a8353960SJulian Elischer 	new_connection->loc = 0;
302a8353960SJulian Elischer 	new_connection->active_hook = hook;
303a8353960SJulian Elischer 
304a8353960SJulian Elischer 	SLIST_INSERT_HEAD(&sc->head, new_connection, links);
305a8353960SJulian Elischer 
306a8353960SJulian Elischer 	return(0);
307a8353960SJulian Elischer }
308a8353960SJulian Elischer 
309a8353960SJulian Elischer /*
310a8353960SJulian Elischer  * we gave ok to a new hook
311a8353960SJulian Elischer  * now connect
312a8353960SJulian Elischer  */
313a8353960SJulian Elischer static int
314a8353960SJulian Elischer ng_device_connect(hook_p hook)
315a8353960SJulian Elischer {
316a8353960SJulian Elischer 
317a8353960SJulian Elischer #ifdef NGD_DEBUG
318a8353960SJulian Elischer 	printf("%s()\n",__func__);
319a8353960SJulian Elischer #endif /* NGD_DEBUG */
320a8353960SJulian Elischer 
321a8353960SJulian Elischer 	return(0);
322a8353960SJulian Elischer }
323a8353960SJulian Elischer 
324a8353960SJulian Elischer 
325a8353960SJulian Elischer /*
326a8353960SJulian Elischer  * Receive data from hook
327a8353960SJulian Elischer  */
328a8353960SJulian Elischer static int
329a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item)
330a8353960SJulian Elischer {
331a8353960SJulian Elischer 	struct mbuf *m;
332a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
333a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
334a8353960SJulian Elischer 	struct ngd_connection * tmp;
335a8353960SJulian Elischer 	char *buffer;
336a8353960SJulian Elischer 
337a8353960SJulian Elischer #ifdef NGD_DEBUG
338a8353960SJulian Elischer 	printf("%s()\n",__func__);
339a8353960SJulian Elischer #endif /* NGD_DEBUG */
340a8353960SJulian Elischer 
341a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
342a8353960SJulian Elischer 		if(tmp->active_hook == hook) {
343a8353960SJulian Elischer 			connection = tmp;
344a8353960SJulian Elischer 		}
345a8353960SJulian Elischer 	}
346a8353960SJulian Elischer 	if(connection == NULL) {
347a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
348a8353960SJulian Elischer 		return(-1);
349a8353960SJulian Elischer 	}
350a8353960SJulian Elischer 
351a8353960SJulian Elischer 	NGI_GET_M(item, m);
352a8353960SJulian Elischer 	NG_FREE_ITEM(item);
353a8353960SJulian Elischer 
354a8353960SJulian Elischer 	m = m_pullup(m,m->m_len);
355a8353960SJulian Elischer 	if(m == NULL) {
356a8353960SJulian Elischer 		printf("%s(): ERROR: m_pullup failed\n",__func__);
357a8353960SJulian Elischer 		return(-1);
358a8353960SJulian Elischer 	}
359a8353960SJulian Elischer 
360a8353960SJulian Elischer 	buffer = malloc(sizeof(char)*m->m_len, M_DEVBUF, M_NOWAIT | M_ZERO);
361a8353960SJulian Elischer 	if(buffer == NULL) {
362a8353960SJulian Elischer 		printf("%s(): ERROR: buffer malloc failed\n",__func__);
363a8353960SJulian Elischer 		return(-1);
364a8353960SJulian Elischer 	}
365a8353960SJulian Elischer 
366a8353960SJulian Elischer 	buffer = mtod(m,char *);
367a8353960SJulian Elischer 
368a8353960SJulian Elischer 	if( (connection->loc+m->m_len) < NGD_QUEUE_SIZE) {
369a8353960SJulian Elischer 	        memcpy(connection->readq+connection->loc, buffer, m->m_len);
370a8353960SJulian Elischer 		connection->loc += m->m_len;
371a8353960SJulian Elischer 	} else
372a8353960SJulian Elischer 		printf("%s(): queue full, first read out a bit\n",__func__);
373a8353960SJulian Elischer 
374a8353960SJulian Elischer 	free(buffer,M_DEVBUF);
375a8353960SJulian Elischer 
376a8353960SJulian Elischer 	return(0);
377a8353960SJulian Elischer }
378a8353960SJulian Elischer 
379a8353960SJulian Elischer /*
380a8353960SJulian Elischer  * Removal of the last link destroys the node
381a8353960SJulian Elischer  */
382a8353960SJulian Elischer static int
383a8353960SJulian Elischer ng_device_disconnect(hook_p hook)
384a8353960SJulian Elischer {
385a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
386a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
387a8353960SJulian Elischer 	struct ngd_connection * tmp;
388a8353960SJulian Elischer 
389a8353960SJulian Elischer #ifdef NGD_DEBUG
390a8353960SJulian Elischer 	printf("%s()\n",__func__);
391a8353960SJulian Elischer #endif /* NGD_DEBUG */
392a8353960SJulian Elischer 
393a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
394a8353960SJulian Elischer 		if(tmp->active_hook == hook) {
395a8353960SJulian Elischer 			connection = tmp;
396a8353960SJulian Elischer 		}
397a8353960SJulian Elischer 	}
398a8353960SJulian Elischer 	if(connection == NULL) {
399a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no hook found\n",__func__);
400a8353960SJulian Elischer 		return(-1);
401a8353960SJulian Elischer 	}
402a8353960SJulian Elischer 
403a8353960SJulian Elischer         free(connection->readq,M_DEVBUF);
404a8353960SJulian Elischer 
405a8353960SJulian Elischer 	destroy_dev(connection->ngddev);
406a8353960SJulian Elischer 
407a8353960SJulian Elischer 	SLIST_REMOVE(&sc->head,connection,ngd_connection,links);
408a8353960SJulian Elischer 
409a8353960SJulian Elischer 	return(0);
410a8353960SJulian Elischer }
411a8353960SJulian Elischer /*
412a8353960SJulian Elischer  * the device is opened
413a8353960SJulian Elischer  */
414a8353960SJulian Elischer static int
415a8353960SJulian Elischer ngdopen(dev_t dev, int flag, int mode, struct thread *td)
416a8353960SJulian Elischer {
417a8353960SJulian Elischer 
418a8353960SJulian Elischer #ifdef NGD_DEBUG
419a8353960SJulian Elischer 	printf("%s()\n",__func__);
420a8353960SJulian Elischer #endif /* NGD_DEBUG */
421a8353960SJulian Elischer 
422a8353960SJulian Elischer 	return(0);
423a8353960SJulian Elischer }
424a8353960SJulian Elischer 
425a8353960SJulian Elischer /*
426a8353960SJulian Elischer  * the device is closed
427a8353960SJulian Elischer  */
428a8353960SJulian Elischer static int
429a8353960SJulian Elischer ngdclose(dev_t dev, int flag, int mode, struct thread *td)
430a8353960SJulian Elischer {
431a8353960SJulian Elischer 
432a8353960SJulian Elischer #ifdef NGD_DEBUG
433a8353960SJulian Elischer 	printf("%s()\n",__func__);
434a8353960SJulian Elischer #endif
435a8353960SJulian Elischer 
436a8353960SJulian Elischer 	return(0);
437a8353960SJulian Elischer }
438a8353960SJulian Elischer 
439a8353960SJulian Elischer 
440a8353960SJulian Elischer /*
441a8353960SJulian Elischer  * process ioctl
442a8353960SJulian Elischer  *
443a8353960SJulian Elischer  * they are translated into netgraph messages and passed on
444a8353960SJulian Elischer  *
445a8353960SJulian Elischer  */
446a8353960SJulian Elischer static int
447a8353960SJulian Elischer ngdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
448a8353960SJulian Elischer {
449a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
450a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
451a8353960SJulian Elischer 	struct ngd_connection * tmp;
452a8353960SJulian Elischer 	int error = 0;
453a8353960SJulian Elischer 	struct ng_mesg *msg;
454a8353960SJulian Elischer         struct ngd_param_s * datap;
455a8353960SJulian Elischer 
456a8353960SJulian Elischer #ifdef NGD_DEBUG
457a8353960SJulian Elischer 	printf("%s()\n",__func__);
458a8353960SJulian Elischer #endif /* NGD_DEBUG */
459a8353960SJulian Elischer 
460a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
461a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
462a8353960SJulian Elischer 			connection = tmp;
463a8353960SJulian Elischer 		}
464a8353960SJulian Elischer 	}
465a8353960SJulian Elischer 	if(connection == NULL) {
466a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
467a8353960SJulian Elischer 		return(-1);
468a8353960SJulian Elischer 	}
469a8353960SJulian Elischer 
470a8353960SJulian Elischer 	/* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */
471a8353960SJulian Elischer 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
472a8353960SJulian Elischer 			M_NOWAIT);
473a8353960SJulian Elischer 	if (msg == NULL) {
474a8353960SJulian Elischer 		printf("%s(): msg == NULL\n",__func__);
475a8353960SJulian Elischer 		goto nomsg;
476a8353960SJulian Elischer 	}
477a8353960SJulian Elischer 
478a8353960SJulian Elischer 	/* pass the ioctl data into the ->data area */
479a8353960SJulian Elischer 	datap = (struct ngd_param_s *)msg->data;
480a8353960SJulian Elischer         datap->p = addr;
481a8353960SJulian Elischer 
482a8353960SJulian Elischer 	/* NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr) */
483a8353960SJulian Elischer 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, NULL);
484a8353960SJulian Elischer 	if(error)
485a8353960SJulian Elischer 		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
486a8353960SJulian Elischer 
487a8353960SJulian Elischer nomsg:
488a8353960SJulian Elischer 
489a8353960SJulian Elischer 	return(0);
490a8353960SJulian Elischer }
491a8353960SJulian Elischer 
492a8353960SJulian Elischer 
493a8353960SJulian Elischer /*
494a8353960SJulian Elischer  * This function is called when a read(2) is done to our device.
495a8353960SJulian Elischer  * We pass the data available in kernelspace on into userland using
496a8353960SJulian Elischer  * uiomove.
497a8353960SJulian Elischer  */
498a8353960SJulian Elischer static int
499a8353960SJulian Elischer ngdread(dev_t dev, struct uio *uio, int flag)
500a8353960SJulian Elischer {
501a8353960SJulian Elischer 	int ret = 0, amnt;
502a8353960SJulian Elischer 	char buffer[uio->uio_resid+1];
503a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
504a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
505a8353960SJulian Elischer 	struct ngd_connection * tmp;
506a8353960SJulian Elischer 
507a8353960SJulian Elischer #ifdef NGD_DEBUG
508a8353960SJulian Elischer 	printf("%s()\n",__func__);
509a8353960SJulian Elischer #endif /* NGD_DEBUG */
510a8353960SJulian Elischer 
511a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
512a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
513a8353960SJulian Elischer 			connection = tmp;
514a8353960SJulian Elischer 		}
515a8353960SJulian Elischer 	}
516a8353960SJulian Elischer 	if(connection == NULL) {
517a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
518a8353960SJulian Elischer 		return(-1);
519a8353960SJulian Elischer 	}
520a8353960SJulian Elischer 
521a8353960SJulian Elischer 	while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) {
522a8353960SJulian Elischer 		amnt = MIN(uio->uio_resid,connection->loc);
523a8353960SJulian Elischer 
524a8353960SJulian Elischer 		memcpy(buffer,connection->readq, amnt);
525a8353960SJulian Elischer 		memcpy(connection->readq, connection->readq+amnt,
526a8353960SJulian Elischer 				connection->loc-amnt);
527a8353960SJulian Elischer 		connection->loc -= amnt;
528a8353960SJulian Elischer 
529a8353960SJulian Elischer 		ret = uiomove((caddr_t)buffer, amnt, uio);
530a8353960SJulian Elischer 		if(ret != 0)
531a8353960SJulian Elischer 			goto error;
532a8353960SJulian Elischer 
533a8353960SJulian Elischer 	}
534a8353960SJulian Elischer 	return(0);
535a8353960SJulian Elischer 
536a8353960SJulian Elischer error:
537a8353960SJulian Elischer 	printf("%s(): uiomove returns error %d\n",__func__,ret);
538a8353960SJulian Elischer 	/* do error cleanup here */
539a8353960SJulian Elischer 	return(ret);
540a8353960SJulian Elischer }
541a8353960SJulian Elischer 
542a8353960SJulian Elischer 
543a8353960SJulian Elischer /*
544a8353960SJulian Elischer  * This function is called when our device is written to.
545a8353960SJulian Elischer  * We read the data from userland into our local buffer and pass it on
546a8353960SJulian Elischer  * into the remote hook.
547a8353960SJulian Elischer  *
548a8353960SJulian Elischer  */
549a8353960SJulian Elischer static int
550a8353960SJulian Elischer ngdwrite(dev_t dev, struct uio *uio, int flag)
551a8353960SJulian Elischer {
552a8353960SJulian Elischer 	int ret;
553a8353960SJulian Elischer 	int error = 0;
554a8353960SJulian Elischer 	struct mbuf *m;
555a8353960SJulian Elischer 	char buffer[uio->uio_resid];
556a8353960SJulian Elischer 	int len = uio->uio_resid;
557a8353960SJulian Elischer 	struct ngd_softc *sc =& ngd_softc;
558a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
559a8353960SJulian Elischer 	struct ngd_connection * tmp;
560a8353960SJulian Elischer 
561a8353960SJulian Elischer #ifdef NGD_DEBUG
562a8353960SJulian Elischer 	printf("%s()\n",__func__);
563a8353960SJulian Elischer #endif /* NGD_DEBUG */
564a8353960SJulian Elischer 
565a8353960SJulian Elischer 	SLIST_FOREACH(tmp,&sc->head,links) {
566a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
567a8353960SJulian Elischer 			connection = tmp;
568a8353960SJulian Elischer 		}
569a8353960SJulian Elischer 	}
570a8353960SJulian Elischer 
571a8353960SJulian Elischer 	if(connection == NULL) {
572a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
573a8353960SJulian Elischer 		return(-1);
574a8353960SJulian Elischer 	}
575a8353960SJulian Elischer 
576a8353960SJulian Elischer 	if (len > 0) {
577a8353960SJulian Elischer 		if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0)
578a8353960SJulian Elischer 			goto error;
579a8353960SJulian Elischer 	} else
580a8353960SJulian Elischer 		printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__);
581a8353960SJulian Elischer 
582a8353960SJulian Elischer 	m = m_devget(buffer,len,0,NULL,NULL);
583a8353960SJulian Elischer 
584a8353960SJulian Elischer 	NG_SEND_DATA_ONLY(error,connection->active_hook,m);
585a8353960SJulian Elischer 
586a8353960SJulian Elischer 	return(0);
587a8353960SJulian Elischer 
588a8353960SJulian Elischer error:
589a8353960SJulian Elischer 	/* do error cleanup here */
590a8353960SJulian Elischer 	printf("%s(): uiomove returned err: %d\n",__func__,ret);
591a8353960SJulian Elischer 
592a8353960SJulian Elischer 	return(ret);
593a8353960SJulian Elischer }
594a8353960SJulian Elischer 
595a8353960SJulian Elischer /*
596a8353960SJulian Elischer  * we are being polled/selected
597a8353960SJulian Elischer  * check if there is data available for read
598a8353960SJulian Elischer  */
599a8353960SJulian Elischer static int
600a8353960SJulian Elischer ngdpoll(dev_t dev, int events, struct thread *td)
601a8353960SJulian Elischer {
602a8353960SJulian Elischer 	int revents = 0;
603a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
604a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
605a8353960SJulian Elischer 	struct ngd_connection * tmp;
606a8353960SJulian Elischer 
607a8353960SJulian Elischer 
608a8353960SJulian Elischer 	if (events & (POLLIN | POLLRDNORM)) {
609a8353960SJulian Elischer 		/* get the connection we have to know the loc from */
610a8353960SJulian Elischer 		SLIST_FOREACH(tmp,&sc->head,links) {
611a8353960SJulian Elischer 			if(tmp->ngddev == dev) {
612a8353960SJulian Elischer 				connection = tmp;
613a8353960SJulian Elischer 			}
614a8353960SJulian Elischer 		}
615a8353960SJulian Elischer 		if(connection == NULL) {
616a8353960SJulian Elischer 			printf("%s(): ERROR: connection is still NULL,"
617a8353960SJulian Elischer 				"no dev found\n",__func__);
618a8353960SJulian Elischer 			return(-1);
619a8353960SJulian Elischer 		}
620a8353960SJulian Elischer 
621a8353960SJulian Elischer 		if (connection->loc > 0)
622a8353960SJulian Elischer 			revents |= events & (POLLIN | POLLRDNORM);
623a8353960SJulian Elischer 	}
624a8353960SJulian Elischer 
625a8353960SJulian Elischer 	return(revents);
626a8353960SJulian Elischer }
627