xref: /freebsd/sys/netgraph/ng_device.c (revision 674d86bf9177ff80b5f38f7191951f303a816cac)
1c398230bSWarner Losh /*-
2a8353960SJulian Elischer  * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
35cdd064dSGleb Smirnoff  * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
4a8353960SJulian Elischer  *
5a8353960SJulian Elischer  * Redistribution and use in source and binary forms, with or without
6a8353960SJulian Elischer  * modification, are permitted provided that the following conditions
7a8353960SJulian Elischer  * are met:
8a8353960SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
9a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
10a8353960SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
11a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
12a8353960SJulian Elischer  *    documentation and/or other materials provided with the distribution.
13a8353960SJulian Elischer  *
14a8353960SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15a8353960SJulian Elischer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16a8353960SJulian Elischer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17a8353960SJulian Elischer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18a8353960SJulian Elischer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19a8353960SJulian Elischer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20a8353960SJulian Elischer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21a8353960SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22a8353960SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23a8353960SJulian Elischer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24a8353960SJulian Elischer  *
25a8353960SJulian Elischer  * Netgraph "device" node
26a8353960SJulian Elischer  *
27a8353960SJulian Elischer  * This node presents a /dev/ngd%d device that interfaces to an other
28a8353960SJulian Elischer  * netgraph node.
29a8353960SJulian Elischer  *
30a8353960SJulian Elischer  * $FreeBSD$
31a8353960SJulian Elischer  *
32a8353960SJulian Elischer  */
33a8353960SJulian Elischer 
34547d3473SGleb Smirnoff #if 0
35ec774932SGleb Smirnoff #define	DBG do { printf("ng_device: %s\n", __func__ ); } while (0)
36547d3473SGleb Smirnoff #else
37ec774932SGleb Smirnoff #define	DBG do {} while (0)
38547d3473SGleb Smirnoff #endif
39547d3473SGleb Smirnoff 
40a8353960SJulian Elischer #include <sys/param.h>
41a8353960SJulian Elischer #include <sys/conf.h>
42a8353960SJulian Elischer #include <sys/ioccom.h>
43b3e3ef98SGleb Smirnoff #include <sys/kernel.h>
44b3e3ef98SGleb Smirnoff #include <sys/malloc.h>
45b3e3ef98SGleb Smirnoff #include <sys/mbuf.h>
46b3e3ef98SGleb Smirnoff #include <sys/poll.h>
47b3e3ef98SGleb Smirnoff #include <sys/queue.h>
48547d3473SGleb Smirnoff #include <sys/socket.h>
49b3e3ef98SGleb Smirnoff #include <sys/systm.h>
50b3e3ef98SGleb Smirnoff #include <sys/uio.h>
51547d3473SGleb Smirnoff #include <sys/vnode.h>
52547d3473SGleb Smirnoff 
53547d3473SGleb Smirnoff #include <net/if.h>
54547d3473SGleb Smirnoff #include <net/if_var.h>
55547d3473SGleb Smirnoff #include <netinet/in.h>
56547d3473SGleb Smirnoff #include <netinet/in_systm.h>
57547d3473SGleb Smirnoff #include <netinet/ip.h>
58a8353960SJulian Elischer 
59a8353960SJulian Elischer #include <netgraph/ng_message.h>
60a8353960SJulian Elischer #include <netgraph/netgraph.h>
61b3e3ef98SGleb Smirnoff #include <netgraph/ng_device.h>
62a8353960SJulian Elischer 
63c1eec6c5SGleb Smirnoff #define	ERROUT(x) do { error = (x); goto done; } while (0)
64c1eec6c5SGleb Smirnoff 
65a8353960SJulian Elischer /* Netgraph methods */
6630aabc9aSRuslan Ermilov static int		ng_device_mod_event(module_t, int, void *);
67547d3473SGleb Smirnoff static ng_constructor_t	ng_device_constructor;
68a8353960SJulian Elischer static ng_rcvmsg_t	ng_device_rcvmsg;
69547d3473SGleb Smirnoff static ng_shutdown_t	ng_device_shutdown;
70a8353960SJulian Elischer static ng_newhook_t	ng_device_newhook;
71a8353960SJulian Elischer static ng_rcvdata_t	ng_device_rcvdata;
72a8353960SJulian Elischer static ng_disconnect_t	ng_device_disconnect;
73a8353960SJulian Elischer 
74a8353960SJulian Elischer /* Netgraph type */
75547d3473SGleb Smirnoff static struct ng_type ngd_typestruct = {
76f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
77f8aae777SJulian Elischer 	.name =		NG_DEVICE_NODE_TYPE,
7830aabc9aSRuslan Ermilov 	.mod_event =	ng_device_mod_event,
79547d3473SGleb Smirnoff 	.constructor =	ng_device_constructor,
80f8aae777SJulian Elischer 	.rcvmsg	=	ng_device_rcvmsg,
81547d3473SGleb Smirnoff 	.shutdown = 	ng_device_shutdown,
82f8aae777SJulian Elischer 	.newhook =	ng_device_newhook,
83f8aae777SJulian Elischer 	.rcvdata =	ng_device_rcvdata,
84f8aae777SJulian Elischer 	.disconnect =	ng_device_disconnect,
85a8353960SJulian Elischer };
86547d3473SGleb Smirnoff NETGRAPH_INIT(device, &ngd_typestruct);
87a8353960SJulian Elischer 
88547d3473SGleb Smirnoff /* per node data */
89547d3473SGleb Smirnoff struct ngd_private {
90547d3473SGleb Smirnoff 	struct	ifqueue	readq;
91547d3473SGleb Smirnoff 	struct	ng_node	*node;
92547d3473SGleb Smirnoff 	struct	ng_hook	*hook;
9389c9c53dSPoul-Henning Kamp 	struct	cdev	*ngddev;
94547d3473SGleb Smirnoff 	struct	mtx	ngd_mtx;
95a8353960SJulian Elischer 	int 		unit;
96547d3473SGleb Smirnoff 	uint16_t	flags;
97547d3473SGleb Smirnoff #define	NGDF_OPEN	0x0001
98547d3473SGleb Smirnoff #define	NGDF_RWAIT	0x0002
99a8353960SJulian Elischer };
100547d3473SGleb Smirnoff typedef struct ngd_private *priv_p;
101a8353960SJulian Elischer 
1025cdd064dSGleb Smirnoff /* unit number allocator entity */
1035cdd064dSGleb Smirnoff static struct unrhdr *ngd_unit;
104a8353960SJulian Elischer 
105a8353960SJulian Elischer /* Maximum number of NGD devices */
1065cdd064dSGleb Smirnoff #define MAX_NGD	999
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;
112547d3473SGleb Smirnoff #if 0
113a8353960SJulian Elischer static d_ioctl_t ngdioctl;
114547d3473SGleb Smirnoff #endif
115a8353960SJulian Elischer static d_poll_t ngdpoll;
116a8353960SJulian Elischer 
117a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = {
118dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
1197ac40f5fSPoul-Henning Kamp 	.d_open =	ngdopen,
1207ac40f5fSPoul-Henning Kamp 	.d_close =	ngdclose,
1217ac40f5fSPoul-Henning Kamp 	.d_read =	ngdread,
1227ac40f5fSPoul-Henning Kamp 	.d_write =	ngdwrite,
123547d3473SGleb Smirnoff #if 0
1247ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ngdioctl,
125547d3473SGleb Smirnoff #endif
1267ac40f5fSPoul-Henning Kamp 	.d_poll =	ngdpoll,
127547d3473SGleb Smirnoff 	.d_name =	NG_DEVICE_DEVNAME,
128a8353960SJulian Elischer };
129a8353960SJulian Elischer 
130547d3473SGleb Smirnoff /******************************************************************************
131547d3473SGleb Smirnoff  *  Netgraph methods
132547d3473SGleb Smirnoff  ******************************************************************************/
133547d3473SGleb Smirnoff 
134a8353960SJulian Elischer /*
1355cdd064dSGleb Smirnoff  * Handle loading and unloading for this node type.
1365cdd064dSGleb Smirnoff  */
1375cdd064dSGleb Smirnoff static int
1385cdd064dSGleb Smirnoff ng_device_mod_event(module_t mod, int event, void *data)
1395cdd064dSGleb Smirnoff {
1405cdd064dSGleb Smirnoff 	int error = 0;
1415cdd064dSGleb Smirnoff 
1425cdd064dSGleb Smirnoff 	switch (event) {
1435cdd064dSGleb Smirnoff 	case MOD_LOAD:
1445cdd064dSGleb Smirnoff 		ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
1455cdd064dSGleb Smirnoff 		break;
1465cdd064dSGleb Smirnoff 	case MOD_UNLOAD:
1475cdd064dSGleb Smirnoff 		delete_unrhdr(ngd_unit);
1485cdd064dSGleb Smirnoff 		break;
1495cdd064dSGleb Smirnoff 	default:
1505cdd064dSGleb Smirnoff 		error = EOPNOTSUPP;
1515cdd064dSGleb Smirnoff 		break;
1525cdd064dSGleb Smirnoff 	}
1535cdd064dSGleb Smirnoff 	return (error);
1545cdd064dSGleb Smirnoff }
1555cdd064dSGleb Smirnoff 
1565cdd064dSGleb Smirnoff /*
157547d3473SGleb Smirnoff  * create new node
158a8353960SJulian Elischer  */
159a8353960SJulian Elischer static int
160547d3473SGleb Smirnoff ng_device_constructor(node_p node)
161a8353960SJulian Elischer {
162547d3473SGleb Smirnoff 	priv_p	priv;
163a8353960SJulian Elischer 
164f2b9562cSGleb Smirnoff 	DBG;
165a8353960SJulian Elischer 
166*674d86bfSGleb Smirnoff 	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
167a8353960SJulian Elischer 
1685cdd064dSGleb Smirnoff 	/* Allocate unit number */
1695cdd064dSGleb Smirnoff 	priv->unit = alloc_unr(ngd_unit);
170a8353960SJulian Elischer 
171843cfd5aSGleb Smirnoff 	/* Initialize mutexes and queue */
172843cfd5aSGleb Smirnoff 	mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
173547d3473SGleb Smirnoff 	mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
174547d3473SGleb Smirnoff 	IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
175a8353960SJulian Elischer 
176547d3473SGleb Smirnoff 	/* Link everything together */
177547d3473SGleb Smirnoff 	NG_NODE_SET_PRIVATE(node, priv);
178547d3473SGleb Smirnoff 	priv->node = node;
179a8353960SJulian Elischer 
180d3ce8327SEd Schouten 	priv->ngddev = make_dev(&ngd_cdevsw, priv->unit, UID_ROOT,
181843cfd5aSGleb Smirnoff 	    GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
182843cfd5aSGleb Smirnoff 	if(priv->ngddev == NULL) {
183843cfd5aSGleb Smirnoff 		printf("%s(): make_dev() failed\n",__func__);
184843cfd5aSGleb Smirnoff 		mtx_destroy(&priv->ngd_mtx);
185843cfd5aSGleb Smirnoff 		mtx_destroy(&priv->readq.ifq_mtx);
1865cdd064dSGleb Smirnoff 		free_unr(ngd_unit, priv->unit);
1871ede983cSDag-Erling Smørgrav 		free(priv, M_NETGRAPH);
188843cfd5aSGleb Smirnoff 		return(EINVAL);
189843cfd5aSGleb Smirnoff 	}
190843cfd5aSGleb Smirnoff 	/* XXX: race here? */
191843cfd5aSGleb Smirnoff 	priv->ngddev->si_drv1 = priv;
192a8353960SJulian Elischer 
193a8353960SJulian Elischer 	return(0);
194a8353960SJulian Elischer }
195a8353960SJulian Elischer 
196a8353960SJulian Elischer /*
197547d3473SGleb Smirnoff  * Process control message.
198a8353960SJulian Elischer  */
199a8353960SJulian Elischer 
200a8353960SJulian Elischer static int
201a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
202a8353960SJulian Elischer {
203547d3473SGleb Smirnoff 	const priv_p priv = NG_NODE_PRIVATE(node);
204a8353960SJulian Elischer 	struct ng_mesg *msg;
205547d3473SGleb Smirnoff 	struct ng_mesg *resp = NULL;
206a8353960SJulian Elischer 	int error = 0;
207a8353960SJulian Elischer 
208a8353960SJulian Elischer 	NGI_GET_MSG(item, msg);
209a8353960SJulian Elischer 
210547d3473SGleb Smirnoff 	if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
211547d3473SGleb Smirnoff 		switch (msg->header.cmd) {
212547d3473SGleb Smirnoff 		case NGM_DEVICE_GET_DEVNAME:
2135cdd064dSGleb Smirnoff 			/* XXX: Fix when MAX_NGD us bigger */
214547d3473SGleb Smirnoff 			NG_MKRESPONSE(resp, msg,
2155cdd064dSGleb Smirnoff 			    strlen(NG_DEVICE_DEVNAME) + 4, M_NOWAIT);
216a8353960SJulian Elischer 
217547d3473SGleb Smirnoff 			if (resp == NULL)
218547d3473SGleb Smirnoff 				ERROUT(ENOMEM);
219547d3473SGleb Smirnoff 
220547d3473SGleb Smirnoff 			strlcpy((char *)resp->data, priv->ngddev->si_name,
221547d3473SGleb Smirnoff 			    strlen(priv->ngddev->si_name) + 1);
222547d3473SGleb Smirnoff 			break;
223547d3473SGleb Smirnoff 
224547d3473SGleb Smirnoff 		default:
225547d3473SGleb Smirnoff 			error = EINVAL;
226547d3473SGleb Smirnoff 			break;
227547d3473SGleb Smirnoff 		}
228547d3473SGleb Smirnoff 	} else
229547d3473SGleb Smirnoff 		error = EINVAL;
230547d3473SGleb Smirnoff 
231547d3473SGleb Smirnoff done:
232547d3473SGleb Smirnoff 	NG_RESPOND_MSG(error, node, item, resp);
233547d3473SGleb Smirnoff 	NG_FREE_MSG(msg);
234a8353960SJulian Elischer 	return (error);
235a8353960SJulian Elischer }
236a8353960SJulian Elischer 
237a8353960SJulian Elischer /*
238547d3473SGleb Smirnoff  * Accept incoming hook. We support only one hook per node.
239a8353960SJulian Elischer  */
240a8353960SJulian Elischer static int
241a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name)
242a8353960SJulian Elischer {
243547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(node);
244a8353960SJulian Elischer 
245f2b9562cSGleb Smirnoff 	DBG;
246a8353960SJulian Elischer 
247547d3473SGleb Smirnoff 	/* We have only one hook per node */
248547d3473SGleb Smirnoff 	if (priv->hook != NULL)
249547d3473SGleb Smirnoff 		return (EISCONN);
250a8353960SJulian Elischer 
251547d3473SGleb Smirnoff 	priv->hook = hook;
252a8353960SJulian Elischer 
253a8353960SJulian Elischer 	return(0);
254a8353960SJulian Elischer }
255a8353960SJulian Elischer 
256a8353960SJulian Elischer /*
257547d3473SGleb Smirnoff  * Receive data from hook, write it to device.
258a8353960SJulian Elischer  */
259a8353960SJulian Elischer static int
260a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item)
261a8353960SJulian Elischer {
262547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
263a8353960SJulian Elischer 	struct mbuf *m;
264a8353960SJulian Elischer 
265f2b9562cSGleb Smirnoff 	DBG;
266a8353960SJulian Elischer 
267a8353960SJulian Elischer 	NGI_GET_M(item, m);
268a8353960SJulian Elischer 	NG_FREE_ITEM(item);
269a8353960SJulian Elischer 
270547d3473SGleb Smirnoff 	IF_LOCK(&priv->readq);
271547d3473SGleb Smirnoff 	if (_IF_QFULL(&priv->readq)) {
272547d3473SGleb Smirnoff 		_IF_DROP(&priv->readq);
273547d3473SGleb Smirnoff 		IF_UNLOCK(&priv->readq);
274c1eec6c5SGleb Smirnoff 		NG_FREE_M(m);
275547d3473SGleb Smirnoff 		return (ENOBUFS);
276547d3473SGleb Smirnoff 	}
277547d3473SGleb Smirnoff 
278547d3473SGleb Smirnoff 	_IF_ENQUEUE(&priv->readq, m);
279547d3473SGleb Smirnoff 	IF_UNLOCK(&priv->readq);
280547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
281547d3473SGleb Smirnoff 	if (priv->flags & NGDF_RWAIT) {
282547d3473SGleb Smirnoff 		priv->flags &= ~NGDF_RWAIT;
283547d3473SGleb Smirnoff 		wakeup(priv);
284547d3473SGleb Smirnoff 	}
285547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
286547d3473SGleb Smirnoff 
287547d3473SGleb Smirnoff 	return(0);
288a8353960SJulian Elischer }
289a8353960SJulian Elischer 
290a8353960SJulian Elischer /*
291547d3473SGleb Smirnoff  * Removal of the hook destroys the node.
292a8353960SJulian Elischer  */
293a8353960SJulian Elischer static int
294a8353960SJulian Elischer ng_device_disconnect(hook_p hook)
295a8353960SJulian Elischer {
296547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
297a8353960SJulian Elischer 
298f2b9562cSGleb Smirnoff 	DBG;
299a8353960SJulian Elischer 
300547d3473SGleb Smirnoff 	destroy_dev(priv->ngddev);
301547d3473SGleb Smirnoff 	mtx_destroy(&priv->ngd_mtx);
302c1eec6c5SGleb Smirnoff 
303547d3473SGleb Smirnoff 	IF_DRAIN(&priv->readq);
304547d3473SGleb Smirnoff 	mtx_destroy(&(priv)->readq.ifq_mtx);
305a8353960SJulian Elischer 
3065cdd064dSGleb Smirnoff 	free_unr(ngd_unit, priv->unit);
3075cdd064dSGleb Smirnoff 
3081ede983cSDag-Erling Smørgrav 	free(priv, M_NETGRAPH);
309a8353960SJulian Elischer 
310547d3473SGleb Smirnoff 	ng_rmnode_self(NG_HOOK_NODE(hook));
311a8353960SJulian Elischer 
312a8353960SJulian Elischer 	return(0);
313a8353960SJulian Elischer }
314547d3473SGleb Smirnoff 
315547d3473SGleb Smirnoff /*
316547d3473SGleb Smirnoff  * Node shutdown. Everything is already done in disconnect method.
317547d3473SGleb Smirnoff  */
318547d3473SGleb Smirnoff static int
319547d3473SGleb Smirnoff ng_device_shutdown(node_p node)
320547d3473SGleb Smirnoff {
321547d3473SGleb Smirnoff 	NG_NODE_UNREF(node);
322547d3473SGleb Smirnoff 	return (0);
323547d3473SGleb Smirnoff }
324547d3473SGleb Smirnoff 
325547d3473SGleb Smirnoff /******************************************************************************
326547d3473SGleb Smirnoff  *  Device methods
327547d3473SGleb Smirnoff  ******************************************************************************/
328547d3473SGleb Smirnoff 
329a8353960SJulian Elischer /*
330a8353960SJulian Elischer  * the device is opened
331a8353960SJulian Elischer  */
332a8353960SJulian Elischer static int
33389c9c53dSPoul-Henning Kamp ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
334a8353960SJulian Elischer {
335547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
336a8353960SJulian Elischer 
337f2b9562cSGleb Smirnoff 	DBG;
338f2b9562cSGleb Smirnoff 
339547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
340547d3473SGleb Smirnoff 	priv->flags |= NGDF_OPEN;
341547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
342a8353960SJulian Elischer 
343a8353960SJulian Elischer 	return(0);
344a8353960SJulian Elischer }
345a8353960SJulian Elischer 
346a8353960SJulian Elischer /*
347a8353960SJulian Elischer  * the device is closed
348a8353960SJulian Elischer  */
349a8353960SJulian Elischer static int
35089c9c53dSPoul-Henning Kamp ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
351a8353960SJulian Elischer {
352547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
353a8353960SJulian Elischer 
354f2b9562cSGleb Smirnoff 	DBG;
355547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
356547d3473SGleb Smirnoff 	priv->flags &= ~NGDF_OPEN;
357547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
358a8353960SJulian Elischer 
359a8353960SJulian Elischer 	return(0);
360a8353960SJulian Elischer }
361a8353960SJulian Elischer 
362547d3473SGleb Smirnoff #if 0	/*
363547d3473SGleb Smirnoff 	 * The ioctl is transformed into netgraph control message.
364547d3473SGleb Smirnoff 	 * We do not process them, yet.
365547d3473SGleb Smirnoff 	 */
366a8353960SJulian Elischer /*
367a8353960SJulian Elischer  * process ioctl
368a8353960SJulian Elischer  *
369a8353960SJulian Elischer  * they are translated into netgraph messages and passed on
370a8353960SJulian Elischer  *
371a8353960SJulian Elischer  */
372a8353960SJulian Elischer static int
37389c9c53dSPoul-Henning Kamp ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
374a8353960SJulian Elischer {
375a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
376a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
377a8353960SJulian Elischer 	struct ngd_connection * tmp;
378a8353960SJulian Elischer 	int error = 0;
379a8353960SJulian Elischer 	struct ng_mesg *msg;
380a8353960SJulian Elischer 	struct ngd_param_s * datap;
381a8353960SJulian Elischer 
382f2b9562cSGleb Smirnoff 	DBG;
383a8353960SJulian Elischer 
384a8353960SJulian Elischer 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
385a8353960SJulian Elischer 			M_NOWAIT);
386a8353960SJulian Elischer 	if (msg == NULL) {
387a8353960SJulian Elischer 		printf("%s(): msg == NULL\n",__func__);
388a8353960SJulian Elischer 		goto nomsg;
389a8353960SJulian Elischer 	}
390a8353960SJulian Elischer 
391a8353960SJulian Elischer 	/* pass the ioctl data into the ->data area */
392a8353960SJulian Elischer 	datap = (struct ngd_param_s *)msg->data;
393a8353960SJulian Elischer 	datap->p = addr;
394a8353960SJulian Elischer 
395b3e3ef98SGleb Smirnoff 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
396a8353960SJulian Elischer 	if(error)
397a8353960SJulian Elischer 		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
398a8353960SJulian Elischer 
399a8353960SJulian Elischer nomsg:
400a8353960SJulian Elischer 
401a8353960SJulian Elischer 	return(0);
402a8353960SJulian Elischer }
403547d3473SGleb Smirnoff #endif /* if 0 */
404a8353960SJulian Elischer 
405a8353960SJulian Elischer /*
406a8353960SJulian Elischer  * This function is called when a read(2) is done to our device.
407547d3473SGleb Smirnoff  * We process one mbuf from queue.
408a8353960SJulian Elischer  */
409a8353960SJulian Elischer static int
41089c9c53dSPoul-Henning Kamp ngdread(struct cdev *dev, struct uio *uio, int flag)
411a8353960SJulian Elischer {
412547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
413547d3473SGleb Smirnoff 	struct mbuf *m;
414547d3473SGleb Smirnoff 	int len, error = 0;
415a8353960SJulian Elischer 
416f2b9562cSGleb Smirnoff 	DBG;
417a8353960SJulian Elischer 
418547d3473SGleb Smirnoff 	/* get an mbuf */
419547d3473SGleb Smirnoff 	do {
420547d3473SGleb Smirnoff 		IF_DEQUEUE(&priv->readq, m);
421547d3473SGleb Smirnoff 		if (m == NULL) {
422547d3473SGleb Smirnoff 			if (flag & IO_NDELAY)
423547d3473SGleb Smirnoff 				return (EWOULDBLOCK);
424547d3473SGleb Smirnoff 			mtx_lock(&priv->ngd_mtx);
425547d3473SGleb Smirnoff 			priv->flags |= NGDF_RWAIT;
42647095f77SRoman Kurakin 			if ((error = msleep(priv, &priv->ngd_mtx,
42747095f77SRoman Kurakin 			    PDROP | PCATCH | (PZERO + 1),
428547d3473SGleb Smirnoff 			    "ngdread", 0)) != 0)
429547d3473SGleb Smirnoff 				return (error);
430a8353960SJulian Elischer 		}
431547d3473SGleb Smirnoff 	} while (m == NULL);
432547d3473SGleb Smirnoff 
433547d3473SGleb Smirnoff 	while (m && uio->uio_resid > 0 && error == 0) {
434547d3473SGleb Smirnoff 		len = MIN(uio->uio_resid, m->m_len);
435547d3473SGleb Smirnoff 		if (len != 0)
436547d3473SGleb Smirnoff 			error = uiomove(mtod(m, void *), len, uio);
437547d3473SGleb Smirnoff 		m = m_free(m);
438a8353960SJulian Elischer 	}
439a8353960SJulian Elischer 
440547d3473SGleb Smirnoff 	if (m)
441547d3473SGleb Smirnoff 		m_freem(m);
442a8353960SJulian Elischer 
443547d3473SGleb Smirnoff 	return (error);
444a8353960SJulian Elischer }
445a8353960SJulian Elischer 
446a8353960SJulian Elischer 
447a8353960SJulian Elischer /*
448a8353960SJulian Elischer  * This function is called when our device is written to.
449547d3473SGleb Smirnoff  * We read the data from userland into mbuf chain and pass it to the remote hook.
450a8353960SJulian Elischer  *
451a8353960SJulian Elischer  */
452a8353960SJulian Elischer static int
45389c9c53dSPoul-Henning Kamp ngdwrite(struct cdev *dev, struct uio *uio, int flag)
454a8353960SJulian Elischer {
455547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
456a8353960SJulian Elischer 	struct mbuf *m;
457547d3473SGleb Smirnoff 	int error = 0;
458a8353960SJulian Elischer 
459f2b9562cSGleb Smirnoff 	DBG;
460a8353960SJulian Elischer 
461547d3473SGleb Smirnoff 	if (uio->uio_resid == 0)
462a8353960SJulian Elischer 		return (0);
463a8353960SJulian Elischer 
464547d3473SGleb Smirnoff 	if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
465547d3473SGleb Smirnoff 		return (EIO);
466a8353960SJulian Elischer 
4675e20f43dSAndre Oppermann 	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, 0, M_PKTHDR)) == NULL)
468547d3473SGleb Smirnoff 		return (ENOBUFS);
469547d3473SGleb Smirnoff 
470547d3473SGleb Smirnoff 	NG_SEND_DATA_ONLY(error, priv->hook, m);
471547d3473SGleb Smirnoff 
472547d3473SGleb Smirnoff 	return (error);
473a8353960SJulian Elischer }
474a8353960SJulian Elischer 
475a8353960SJulian Elischer /*
476a8353960SJulian Elischer  * we are being polled/selected
477a8353960SJulian Elischer  * check if there is data available for read
478a8353960SJulian Elischer  */
479a8353960SJulian Elischer static int
48089c9c53dSPoul-Henning Kamp ngdpoll(struct cdev *dev, int events, struct thread *td)
481a8353960SJulian Elischer {
482547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
483a8353960SJulian Elischer 	int revents = 0;
484a8353960SJulian Elischer 
485547d3473SGleb Smirnoff 	if (events & (POLLIN | POLLRDNORM) &&
486547d3473SGleb Smirnoff 	    !IFQ_IS_EMPTY(&priv->readq))
487a8353960SJulian Elischer 		revents |= events & (POLLIN | POLLRDNORM);
488a8353960SJulian Elischer 
489a8353960SJulian Elischer 	return (revents);
490a8353960SJulian Elischer }
491