xref: /dragonfly/sys/netgraph7/ng_device.c (revision b5523eac)
1b06ebda0SMatthew Dillon /*-
2b06ebda0SMatthew Dillon  * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
3b06ebda0SMatthew Dillon  * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
4b06ebda0SMatthew Dillon  *
5b06ebda0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6b06ebda0SMatthew Dillon  * modification, are permitted provided that the following conditions
7b06ebda0SMatthew Dillon  * are met:
8b06ebda0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
9b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
10b06ebda0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
11b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
12b06ebda0SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
13b06ebda0SMatthew Dillon  *
14b06ebda0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15b06ebda0SMatthew Dillon  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16b06ebda0SMatthew Dillon  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17b06ebda0SMatthew Dillon  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18b06ebda0SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19b06ebda0SMatthew Dillon  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20b06ebda0SMatthew Dillon  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21b06ebda0SMatthew Dillon  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22b06ebda0SMatthew Dillon  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23b06ebda0SMatthew Dillon  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24b06ebda0SMatthew Dillon  *
25b06ebda0SMatthew Dillon  * Netgraph "device" node
26b06ebda0SMatthew Dillon  *
27b06ebda0SMatthew Dillon  * This node presents a /dev/ngd%d device that interfaces to an other
28b06ebda0SMatthew Dillon  * netgraph node.
29b06ebda0SMatthew Dillon  *
30b06ebda0SMatthew Dillon  * $FreeBSD: src/sys/netgraph/ng_device.c,v 1.22 2006/11/02 17:37:21 andre Exp $
31b06ebda0SMatthew Dillon  *
32b06ebda0SMatthew Dillon  */
33b06ebda0SMatthew Dillon 
34b06ebda0SMatthew Dillon #if 0
35a62226e4SSascha Wildner #define	DBG do { kprintf("ng_device: %s\n", __func__ ); } while (0)
36b06ebda0SMatthew Dillon #else
37b06ebda0SMatthew Dillon #define	DBG do {} while (0)
38b06ebda0SMatthew Dillon #endif
39b06ebda0SMatthew Dillon 
40b06ebda0SMatthew Dillon #include <sys/param.h>
41b06ebda0SMatthew Dillon #include <sys/conf.h>
42b06ebda0SMatthew Dillon #include <sys/kernel.h>
43b06ebda0SMatthew Dillon #include <sys/malloc.h>
44b06ebda0SMatthew Dillon #include <sys/mbuf.h>
45b06ebda0SMatthew Dillon #include <sys/poll.h>
46b06ebda0SMatthew Dillon #include <sys/queue.h>
47b06ebda0SMatthew Dillon #include <sys/socket.h>
48b06ebda0SMatthew Dillon #include <sys/systm.h>
49b06ebda0SMatthew Dillon #include <sys/uio.h>
50b06ebda0SMatthew Dillon #include <sys/vnode.h>
51b06ebda0SMatthew Dillon 
52b06ebda0SMatthew Dillon #include <net/if.h>
53b06ebda0SMatthew Dillon #include <net/if_var.h>
54b06ebda0SMatthew Dillon #include <netinet/in.h>
55b06ebda0SMatthew Dillon #include <netinet/in_systm.h>
56b06ebda0SMatthew Dillon #include <netinet/ip.h>
57b06ebda0SMatthew Dillon 
585a975a3dSMatthew Dillon #include "ng_message.h"
595a975a3dSMatthew Dillon #include "netgraph.h"
605a975a3dSMatthew Dillon #include "ng_device.h"
61b06ebda0SMatthew Dillon 
62b06ebda0SMatthew Dillon #define	ERROUT(x) do { error = (x); goto done; } while (0)
63b06ebda0SMatthew Dillon 
64b06ebda0SMatthew Dillon /* Netgraph methods */
65b06ebda0SMatthew Dillon static int		ng_device_mod_event(module_t, int, void *);
66b06ebda0SMatthew Dillon static ng_constructor_t	ng_device_constructor;
67b06ebda0SMatthew Dillon static ng_rcvmsg_t	ng_device_rcvmsg;
68b06ebda0SMatthew Dillon static ng_shutdown_t	ng_device_shutdown;
69b06ebda0SMatthew Dillon static ng_newhook_t	ng_device_newhook;
70b06ebda0SMatthew Dillon static ng_rcvdata_t	ng_device_rcvdata;
71b06ebda0SMatthew Dillon static ng_disconnect_t	ng_device_disconnect;
72b06ebda0SMatthew Dillon 
73b06ebda0SMatthew Dillon /* Netgraph type */
74b06ebda0SMatthew Dillon static struct ng_type ngd_typestruct = {
75b06ebda0SMatthew Dillon 	.version =	NG_ABI_VERSION,
76b06ebda0SMatthew Dillon 	.name =		NG_DEVICE_NODE_TYPE,
77b06ebda0SMatthew Dillon 	.mod_event =	ng_device_mod_event,
78b06ebda0SMatthew Dillon 	.constructor =	ng_device_constructor,
79b06ebda0SMatthew Dillon 	.rcvmsg	=	ng_device_rcvmsg,
80b06ebda0SMatthew Dillon 	.shutdown = 	ng_device_shutdown,
81b06ebda0SMatthew Dillon 	.newhook =	ng_device_newhook,
82b06ebda0SMatthew Dillon 	.rcvdata =	ng_device_rcvdata,
83b06ebda0SMatthew Dillon 	.disconnect =	ng_device_disconnect,
84b06ebda0SMatthew Dillon };
85b06ebda0SMatthew Dillon NETGRAPH_INIT(device, &ngd_typestruct);
86b06ebda0SMatthew Dillon 
87b06ebda0SMatthew Dillon /* per node data */
88b06ebda0SMatthew Dillon struct ngd_private {
89b06ebda0SMatthew Dillon 	struct	ifqueue	readq;
90b06ebda0SMatthew Dillon 	struct	ng_node	*node;
91b06ebda0SMatthew Dillon 	struct	ng_hook	*hook;
92b06ebda0SMatthew Dillon 	struct	cdev	*ngddev;
93b06ebda0SMatthew Dillon 	struct	mtx	ngd_mtx;
94b06ebda0SMatthew Dillon 	int 		unit;
95b06ebda0SMatthew Dillon 	uint16_t	flags;
96b06ebda0SMatthew Dillon #define	NGDF_OPEN	0x0001
97b06ebda0SMatthew Dillon #define	NGDF_RWAIT	0x0002
98b06ebda0SMatthew Dillon };
99b06ebda0SMatthew Dillon typedef struct ngd_private *priv_p;
100b06ebda0SMatthew Dillon 
101b06ebda0SMatthew Dillon /* unit number allocator entity */
102b06ebda0SMatthew Dillon static struct unrhdr *ngd_unit;
103b06ebda0SMatthew Dillon 
104b06ebda0SMatthew Dillon /* Maximum number of NGD devices */
105b06ebda0SMatthew Dillon #define MAX_NGD	999
106b06ebda0SMatthew Dillon 
107b06ebda0SMatthew Dillon static d_close_t ngdclose;
108b06ebda0SMatthew Dillon static d_open_t ngdopen;
109b06ebda0SMatthew Dillon static d_read_t ngdread;
110b06ebda0SMatthew Dillon static d_write_t ngdwrite;
111b06ebda0SMatthew Dillon #if 0
112b06ebda0SMatthew Dillon static d_ioctl_t ngdioctl;
113b06ebda0SMatthew Dillon #endif
114b06ebda0SMatthew Dillon static d_poll_t ngdpoll;
115b06ebda0SMatthew Dillon 
116b06ebda0SMatthew Dillon static struct cdevsw ngd_cdevsw = {
117b06ebda0SMatthew Dillon 	.d_version =	D_VERSION,
118b06ebda0SMatthew Dillon 	.d_open =	ngdopen,
119b06ebda0SMatthew Dillon 	.d_close =	ngdclose,
120b06ebda0SMatthew Dillon 	.d_read =	ngdread,
121b06ebda0SMatthew Dillon 	.d_write =	ngdwrite,
122b06ebda0SMatthew Dillon #if 0
123b06ebda0SMatthew Dillon 	.d_ioctl =	ngdioctl,
124b06ebda0SMatthew Dillon #endif
125b06ebda0SMatthew Dillon 	.d_poll =	ngdpoll,
126b06ebda0SMatthew Dillon 	.d_name =	NG_DEVICE_DEVNAME,
127b06ebda0SMatthew Dillon };
128b06ebda0SMatthew Dillon 
129b06ebda0SMatthew Dillon /******************************************************************************
130b06ebda0SMatthew Dillon  *  Netgraph methods
131b06ebda0SMatthew Dillon  ******************************************************************************/
132b06ebda0SMatthew Dillon 
133b06ebda0SMatthew Dillon /*
134b06ebda0SMatthew Dillon  * Handle loading and unloading for this node type.
135b06ebda0SMatthew Dillon  */
136b06ebda0SMatthew Dillon static int
ng_device_mod_event(module_t mod,int event,void * data)137b06ebda0SMatthew Dillon ng_device_mod_event(module_t mod, int event, void *data)
138b06ebda0SMatthew Dillon {
139b06ebda0SMatthew Dillon 	int error = 0;
140b06ebda0SMatthew Dillon 
141b06ebda0SMatthew Dillon 	switch (event) {
142b06ebda0SMatthew Dillon 	case MOD_LOAD:
143b06ebda0SMatthew Dillon 		ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
144b06ebda0SMatthew Dillon 		break;
145b06ebda0SMatthew Dillon 	case MOD_UNLOAD:
146b06ebda0SMatthew Dillon 		delete_unrhdr(ngd_unit);
147b06ebda0SMatthew Dillon 		break;
148b06ebda0SMatthew Dillon 	default:
149b06ebda0SMatthew Dillon 		error = EOPNOTSUPP;
150b06ebda0SMatthew Dillon 		break;
151b06ebda0SMatthew Dillon 	}
152b06ebda0SMatthew Dillon 	return (error);
153b06ebda0SMatthew Dillon }
154b06ebda0SMatthew Dillon 
155b06ebda0SMatthew Dillon /*
156b06ebda0SMatthew Dillon  * create new node
157b06ebda0SMatthew Dillon  */
158b06ebda0SMatthew Dillon static int
ng_device_constructor(node_p node)159b06ebda0SMatthew Dillon ng_device_constructor(node_p node)
160b06ebda0SMatthew Dillon {
161b06ebda0SMatthew Dillon 	priv_p	priv;
162b06ebda0SMatthew Dillon 
163b06ebda0SMatthew Dillon 	DBG;
164b06ebda0SMatthew Dillon 
165fc025606SSascha Wildner 	priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
166b06ebda0SMatthew Dillon 
167b06ebda0SMatthew Dillon 	/* Allocate unit number */
168b06ebda0SMatthew Dillon 	priv->unit = alloc_unr(ngd_unit);
169b06ebda0SMatthew Dillon 
170b06ebda0SMatthew Dillon 	/* Initialize mutexes and queue */
171b06ebda0SMatthew Dillon 	mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
172b06ebda0SMatthew Dillon 	mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
173b06ebda0SMatthew Dillon 	IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
174b06ebda0SMatthew Dillon 
175b06ebda0SMatthew Dillon 	/* Link everything together */
176b06ebda0SMatthew Dillon 	NG_NODE_SET_PRIVATE(node, priv);
177b06ebda0SMatthew Dillon 	priv->node = node;
178b06ebda0SMatthew Dillon 
179b06ebda0SMatthew Dillon 	priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT,
180b06ebda0SMatthew Dillon 	    GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
181b06ebda0SMatthew Dillon 	if(priv->ngddev == NULL) {
182a62226e4SSascha Wildner 		kprintf("%s(): make_dev() failed\n",__func__);
183b06ebda0SMatthew Dillon 		mtx_destroy(&priv->ngd_mtx);
184b06ebda0SMatthew Dillon 		mtx_destroy(&priv->readq.ifq_mtx);
185b06ebda0SMatthew Dillon 		free_unr(ngd_unit, priv->unit);
186fc025606SSascha Wildner 		kfree(priv, M_NETGRAPH);
187b06ebda0SMatthew Dillon 		return(EINVAL);
188b06ebda0SMatthew Dillon 	}
189b06ebda0SMatthew Dillon 	/* XXX: race here? */
190b06ebda0SMatthew Dillon 	priv->ngddev->si_drv1 = priv;
191b06ebda0SMatthew Dillon 
192b06ebda0SMatthew Dillon 	return(0);
193b06ebda0SMatthew Dillon }
194b06ebda0SMatthew Dillon 
195b06ebda0SMatthew Dillon /*
196b06ebda0SMatthew Dillon  * Process control message.
197b06ebda0SMatthew Dillon  */
198b06ebda0SMatthew Dillon 
199b06ebda0SMatthew Dillon static int
ng_device_rcvmsg(node_p node,item_p item,hook_p lasthook)200b06ebda0SMatthew Dillon ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
201b06ebda0SMatthew Dillon {
202b06ebda0SMatthew Dillon 	const priv_p priv = NG_NODE_PRIVATE(node);
203b06ebda0SMatthew Dillon 	struct ng_mesg *msg;
204b06ebda0SMatthew Dillon 	struct ng_mesg *resp = NULL;
205b06ebda0SMatthew Dillon 	int error = 0;
206b06ebda0SMatthew Dillon 
207b06ebda0SMatthew Dillon 	NGI_GET_MSG(item, msg);
208b06ebda0SMatthew Dillon 
209b06ebda0SMatthew Dillon 	if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
210b06ebda0SMatthew Dillon 		switch (msg->header.cmd) {
211b06ebda0SMatthew Dillon 		case NGM_DEVICE_GET_DEVNAME:
212b06ebda0SMatthew Dillon 			/* XXX: Fix when MAX_NGD us bigger */
213b06ebda0SMatthew Dillon 			NG_MKRESPONSE(resp, msg,
2145a975a3dSMatthew Dillon 			    strlen(NG_DEVICE_DEVNAME) + 4, M_WAITOK);
215b06ebda0SMatthew Dillon 
216b06ebda0SMatthew Dillon 			if (resp == NULL)
217b06ebda0SMatthew Dillon 				ERROUT(ENOMEM);
218b06ebda0SMatthew Dillon 
219b06ebda0SMatthew Dillon 			strlcpy((char *)resp->data, priv->ngddev->si_name,
220b06ebda0SMatthew Dillon 			    strlen(priv->ngddev->si_name) + 1);
221b06ebda0SMatthew Dillon 			break;
222b06ebda0SMatthew Dillon 
223b06ebda0SMatthew Dillon 		default:
224b06ebda0SMatthew Dillon 			error = EINVAL;
225b06ebda0SMatthew Dillon 			break;
226b06ebda0SMatthew Dillon 		}
227b06ebda0SMatthew Dillon 	} else
228b06ebda0SMatthew Dillon 		error = EINVAL;
229b06ebda0SMatthew Dillon 
230b06ebda0SMatthew Dillon done:
231b06ebda0SMatthew Dillon 	NG_RESPOND_MSG(error, node, item, resp);
232b06ebda0SMatthew Dillon 	NG_FREE_MSG(msg);
233b06ebda0SMatthew Dillon 	return (error);
234b06ebda0SMatthew Dillon }
235b06ebda0SMatthew Dillon 
236b06ebda0SMatthew Dillon /*
237b06ebda0SMatthew Dillon  * Accept incoming hook. We support only one hook per node.
238b06ebda0SMatthew Dillon  */
239b06ebda0SMatthew Dillon static int
ng_device_newhook(node_p node,hook_p hook,const char * name)240b06ebda0SMatthew Dillon ng_device_newhook(node_p node, hook_p hook, const char *name)
241b06ebda0SMatthew Dillon {
242b06ebda0SMatthew Dillon 	priv_p priv = NG_NODE_PRIVATE(node);
243b06ebda0SMatthew Dillon 
244b06ebda0SMatthew Dillon 	DBG;
245b06ebda0SMatthew Dillon 
246b06ebda0SMatthew Dillon 	/* We have only one hook per node */
247b06ebda0SMatthew Dillon 	if (priv->hook != NULL)
248b06ebda0SMatthew Dillon 		return (EISCONN);
249b06ebda0SMatthew Dillon 
250b06ebda0SMatthew Dillon 	priv->hook = hook;
251b06ebda0SMatthew Dillon 
252b06ebda0SMatthew Dillon 	return(0);
253b06ebda0SMatthew Dillon }
254b06ebda0SMatthew Dillon 
255b06ebda0SMatthew Dillon /*
256b06ebda0SMatthew Dillon  * Receive data from hook, write it to device.
257b06ebda0SMatthew Dillon  */
258b06ebda0SMatthew Dillon static int
ng_device_rcvdata(hook_p hook,item_p item)259b06ebda0SMatthew Dillon ng_device_rcvdata(hook_p hook, item_p item)
260b06ebda0SMatthew Dillon {
261b06ebda0SMatthew Dillon 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
262b06ebda0SMatthew Dillon 	struct mbuf *m;
263b06ebda0SMatthew Dillon 
264b06ebda0SMatthew Dillon 	DBG;
265b06ebda0SMatthew Dillon 
266b06ebda0SMatthew Dillon 	NGI_GET_M(item, m);
267b06ebda0SMatthew Dillon 	NG_FREE_ITEM(item);
268b06ebda0SMatthew Dillon 
269b06ebda0SMatthew Dillon 	IF_LOCK(&priv->readq);
270b06ebda0SMatthew Dillon 	if (_IF_QFULL(&priv->readq)) {
271b06ebda0SMatthew Dillon 		_IF_DROP(&priv->readq);
272b06ebda0SMatthew Dillon 		IF_UNLOCK(&priv->readq);
273b06ebda0SMatthew Dillon 		NG_FREE_M(m);
274b06ebda0SMatthew Dillon 		return (ENOBUFS);
275b06ebda0SMatthew Dillon 	}
276b06ebda0SMatthew Dillon 
277b06ebda0SMatthew Dillon 	_IF_ENQUEUE(&priv->readq, m);
278b06ebda0SMatthew Dillon 	IF_UNLOCK(&priv->readq);
279b06ebda0SMatthew Dillon 	mtx_lock(&priv->ngd_mtx);
280b06ebda0SMatthew Dillon 	if (priv->flags & NGDF_RWAIT) {
281b06ebda0SMatthew Dillon 		priv->flags &= ~NGDF_RWAIT;
282b06ebda0SMatthew Dillon 		wakeup(priv);
283b06ebda0SMatthew Dillon 	}
284b06ebda0SMatthew Dillon 	mtx_unlock(&priv->ngd_mtx);
285b06ebda0SMatthew Dillon 
286b06ebda0SMatthew Dillon 	return(0);
287b06ebda0SMatthew Dillon }
288b06ebda0SMatthew Dillon 
289b06ebda0SMatthew Dillon /*
290b06ebda0SMatthew Dillon  * Removal of the hook destroys the node.
291b06ebda0SMatthew Dillon  */
292b06ebda0SMatthew Dillon static int
ng_device_disconnect(hook_p hook)293b06ebda0SMatthew Dillon ng_device_disconnect(hook_p hook)
294b06ebda0SMatthew Dillon {
295b06ebda0SMatthew Dillon 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
296b06ebda0SMatthew Dillon 
297b06ebda0SMatthew Dillon 	DBG;
298b06ebda0SMatthew Dillon 
299b06ebda0SMatthew Dillon 	destroy_dev(priv->ngddev);
300b06ebda0SMatthew Dillon 	mtx_destroy(&priv->ngd_mtx);
301b06ebda0SMatthew Dillon 
302b06ebda0SMatthew Dillon 	IF_DRAIN(&priv->readq);
303b06ebda0SMatthew Dillon 	mtx_destroy(&(priv)->readq.ifq_mtx);
304b06ebda0SMatthew Dillon 
305b06ebda0SMatthew Dillon 	free_unr(ngd_unit, priv->unit);
306b06ebda0SMatthew Dillon 
307fc025606SSascha Wildner 	kfree(priv, M_NETGRAPH);
308b06ebda0SMatthew Dillon 
309b06ebda0SMatthew Dillon 	ng_rmnode_self(NG_HOOK_NODE(hook));
310b06ebda0SMatthew Dillon 
311b06ebda0SMatthew Dillon 	return(0);
312b06ebda0SMatthew Dillon }
313b06ebda0SMatthew Dillon 
314b06ebda0SMatthew Dillon /*
315b06ebda0SMatthew Dillon  * Node shutdown. Everything is already done in disconnect method.
316b06ebda0SMatthew Dillon  */
317b06ebda0SMatthew Dillon static int
ng_device_shutdown(node_p node)318b06ebda0SMatthew Dillon ng_device_shutdown(node_p node)
319b06ebda0SMatthew Dillon {
320b06ebda0SMatthew Dillon 	NG_NODE_UNREF(node);
321b06ebda0SMatthew Dillon 	return (0);
322b06ebda0SMatthew Dillon }
323b06ebda0SMatthew Dillon 
324b06ebda0SMatthew Dillon /******************************************************************************
325b06ebda0SMatthew Dillon  *  Device methods
326b06ebda0SMatthew Dillon  ******************************************************************************/
327b06ebda0SMatthew Dillon 
328b06ebda0SMatthew Dillon /*
329b06ebda0SMatthew Dillon  * the device is opened
330b06ebda0SMatthew Dillon  */
331b06ebda0SMatthew Dillon static int
ngdopen(struct cdev * dev,int flag,int mode,struct thread * td)332b06ebda0SMatthew Dillon ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
333b06ebda0SMatthew Dillon {
334b06ebda0SMatthew Dillon 	priv_p	priv = (priv_p )dev->si_drv1;
335b06ebda0SMatthew Dillon 
336b06ebda0SMatthew Dillon 	DBG;
337b06ebda0SMatthew Dillon 
338b06ebda0SMatthew Dillon 	mtx_lock(&priv->ngd_mtx);
339b06ebda0SMatthew Dillon 	priv->flags |= NGDF_OPEN;
340b06ebda0SMatthew Dillon 	mtx_unlock(&priv->ngd_mtx);
341b06ebda0SMatthew Dillon 
342b06ebda0SMatthew Dillon 	return(0);
343b06ebda0SMatthew Dillon }
344b06ebda0SMatthew Dillon 
345b06ebda0SMatthew Dillon /*
346b06ebda0SMatthew Dillon  * the device is closed
347b06ebda0SMatthew Dillon  */
348b06ebda0SMatthew Dillon static int
ngdclose(struct cdev * dev,int flag,int mode,struct thread * td)349b06ebda0SMatthew Dillon ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
350b06ebda0SMatthew Dillon {
351b06ebda0SMatthew Dillon 	priv_p	priv = (priv_p )dev->si_drv1;
352b06ebda0SMatthew Dillon 
353b06ebda0SMatthew Dillon 	DBG;
354b06ebda0SMatthew Dillon 	mtx_lock(&priv->ngd_mtx);
355b06ebda0SMatthew Dillon 	priv->flags &= ~NGDF_OPEN;
356b06ebda0SMatthew Dillon 	mtx_unlock(&priv->ngd_mtx);
357b06ebda0SMatthew Dillon 
358b06ebda0SMatthew Dillon 	return(0);
359b06ebda0SMatthew Dillon }
360b06ebda0SMatthew Dillon 
361b06ebda0SMatthew Dillon #if 0	/*
362b06ebda0SMatthew Dillon 	 * The ioctl is transformed into netgraph control message.
363b06ebda0SMatthew Dillon 	 * We do not process them, yet.
364b06ebda0SMatthew Dillon 	 */
365b06ebda0SMatthew Dillon /*
366b06ebda0SMatthew Dillon  * process ioctl
367b06ebda0SMatthew Dillon  *
368b06ebda0SMatthew Dillon  * they are translated into netgraph messages and passed on
369b06ebda0SMatthew Dillon  *
370b06ebda0SMatthew Dillon  */
371b06ebda0SMatthew Dillon static int
372b06ebda0SMatthew Dillon ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
373b06ebda0SMatthew Dillon {
374b06ebda0SMatthew Dillon 	struct ngd_softc *sc = &ngd_softc;
375b06ebda0SMatthew Dillon 	struct ngd_connection * connection = NULL;
376b06ebda0SMatthew Dillon 	struct ngd_connection * tmp;
377b06ebda0SMatthew Dillon 	int error = 0;
378b06ebda0SMatthew Dillon 	struct ng_mesg *msg;
379b06ebda0SMatthew Dillon 	struct ngd_param_s * datap;
380b06ebda0SMatthew Dillon 
381b06ebda0SMatthew Dillon 	DBG;
382b06ebda0SMatthew Dillon 
383b06ebda0SMatthew Dillon 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
3845a975a3dSMatthew Dillon 			M_WAITOK);
385b06ebda0SMatthew Dillon 	if (msg == NULL) {
386a62226e4SSascha Wildner 		kprintf("%s(): msg == NULL\n",__func__);
387b06ebda0SMatthew Dillon 		goto nomsg;
388b06ebda0SMatthew Dillon 	}
389b06ebda0SMatthew Dillon 
390b06ebda0SMatthew Dillon 	/* pass the ioctl data into the ->data area */
391b06ebda0SMatthew Dillon 	datap = (struct ngd_param_s *)msg->data;
392b06ebda0SMatthew Dillon 	datap->p = addr;
393b06ebda0SMatthew Dillon 
394b06ebda0SMatthew Dillon 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
395b06ebda0SMatthew Dillon 	if(error)
396a62226e4SSascha Wildner 		kprintf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
397b06ebda0SMatthew Dillon 
398b06ebda0SMatthew Dillon nomsg:
399b06ebda0SMatthew Dillon 
400b06ebda0SMatthew Dillon 	return(0);
401b06ebda0SMatthew Dillon }
402b06ebda0SMatthew Dillon #endif /* if 0 */
403b06ebda0SMatthew Dillon 
404b06ebda0SMatthew Dillon /*
405b06ebda0SMatthew Dillon  * This function is called when a read(2) is done to our device.
406b06ebda0SMatthew Dillon  * We process one mbuf from queue.
407b06ebda0SMatthew Dillon  */
408b06ebda0SMatthew Dillon static int
ngdread(struct cdev * dev,struct uio * uio,int flag)409b06ebda0SMatthew Dillon ngdread(struct cdev *dev, struct uio *uio, int flag)
410b06ebda0SMatthew Dillon {
411b06ebda0SMatthew Dillon 	priv_p	priv = (priv_p )dev->si_drv1;
412b06ebda0SMatthew Dillon 	struct mbuf *m;
413b06ebda0SMatthew Dillon 	int len, error = 0;
414b06ebda0SMatthew Dillon 
415b06ebda0SMatthew Dillon 	DBG;
416b06ebda0SMatthew Dillon 
417b06ebda0SMatthew Dillon 	/* get an mbuf */
418b06ebda0SMatthew Dillon 	do {
419b06ebda0SMatthew Dillon 		IF_DEQUEUE(&priv->readq, m);
420b06ebda0SMatthew Dillon 		if (m == NULL) {
421b06ebda0SMatthew Dillon 			if (flag & IO_NDELAY)
422b06ebda0SMatthew Dillon 				return (EWOULDBLOCK);
423b06ebda0SMatthew Dillon 			mtx_lock(&priv->ngd_mtx);
424b06ebda0SMatthew Dillon 			priv->flags |= NGDF_RWAIT;
425b06ebda0SMatthew Dillon 			if ((error = msleep(priv, &priv->ngd_mtx,
426b06ebda0SMatthew Dillon 			    PDROP | PCATCH | (PZERO + 1),
427b06ebda0SMatthew Dillon 			    "ngdread", 0)) != 0)
428b06ebda0SMatthew Dillon 				return (error);
429b06ebda0SMatthew Dillon 		}
430b06ebda0SMatthew Dillon 	} while (m == NULL);
431b06ebda0SMatthew Dillon 
432b06ebda0SMatthew Dillon 	while (m && uio->uio_resid > 0 && error == 0) {
433b06ebda0SMatthew Dillon 		len = MIN(uio->uio_resid, m->m_len);
434b06ebda0SMatthew Dillon 		if (len != 0)
435b06ebda0SMatthew Dillon 			error = uiomove(mtod(m, void *), len, uio);
436b06ebda0SMatthew Dillon 		m = m_free(m);
437b06ebda0SMatthew Dillon 	}
438b06ebda0SMatthew Dillon 
439b06ebda0SMatthew Dillon 	if (m)
440b06ebda0SMatthew Dillon 		m_freem(m);
441b06ebda0SMatthew Dillon 
442b06ebda0SMatthew Dillon 	return (error);
443b06ebda0SMatthew Dillon }
444b06ebda0SMatthew Dillon 
445b06ebda0SMatthew Dillon 
446b06ebda0SMatthew Dillon /*
447b06ebda0SMatthew Dillon  * This function is called when our device is written to.
448b06ebda0SMatthew Dillon  * We read the data from userland into mbuf chain and pass it to the remote hook.
449b06ebda0SMatthew Dillon  *
450b06ebda0SMatthew Dillon  */
451b06ebda0SMatthew Dillon static int
ngdwrite(struct cdev * dev,struct uio * uio,int flag)452b06ebda0SMatthew Dillon ngdwrite(struct cdev *dev, struct uio *uio, int flag)
453b06ebda0SMatthew Dillon {
454b06ebda0SMatthew Dillon 	priv_p	priv = (priv_p )dev->si_drv1;
455b06ebda0SMatthew Dillon 	struct mbuf *m;
456b06ebda0SMatthew Dillon 	int error = 0;
457b06ebda0SMatthew Dillon 
458b06ebda0SMatthew Dillon 	DBG;
459b06ebda0SMatthew Dillon 
460b06ebda0SMatthew Dillon 	if (uio->uio_resid == 0)
461b06ebda0SMatthew Dillon 		return (0);
462b06ebda0SMatthew Dillon 
463e54488bbSMatthew Dillon 	if (uio->uio_resid > IP_MAXPACKET)
464b06ebda0SMatthew Dillon 		return (EIO);
465b06ebda0SMatthew Dillon 
466*b5523eacSSascha Wildner 	if ((m = m_uiotombuf(uio, M_NOWAIT, 0, 0, M_PKTHDR)) == NULL)
467b06ebda0SMatthew Dillon 		return (ENOBUFS);
468b06ebda0SMatthew Dillon 
469b06ebda0SMatthew Dillon 	NG_SEND_DATA_ONLY(error, priv->hook, m);
470b06ebda0SMatthew Dillon 
471b06ebda0SMatthew Dillon 	return (error);
472b06ebda0SMatthew Dillon }
473b06ebda0SMatthew Dillon 
474b06ebda0SMatthew Dillon /*
475b06ebda0SMatthew Dillon  * we are being polled/selected
476b06ebda0SMatthew Dillon  * check if there is data available for read
477b06ebda0SMatthew Dillon  */
478b06ebda0SMatthew Dillon static int
ngdpoll(struct cdev * dev,int events,struct thread * td)479b06ebda0SMatthew Dillon ngdpoll(struct cdev *dev, int events, struct thread *td)
480b06ebda0SMatthew Dillon {
481b06ebda0SMatthew Dillon 	priv_p	priv = (priv_p )dev->si_drv1;
482b06ebda0SMatthew Dillon 	int revents = 0;
483b06ebda0SMatthew Dillon 
484b06ebda0SMatthew Dillon 	if (events & (POLLIN | POLLRDNORM) &&
485b06ebda0SMatthew Dillon 	    !IFQ_IS_EMPTY(&priv->readq))
486b06ebda0SMatthew Dillon 		revents |= events & (POLLIN | POLLRDNORM);
487b06ebda0SMatthew Dillon 
488b06ebda0SMatthew Dillon 	return (revents);
489b06ebda0SMatthew Dillon }
490