xref: /freebsd/sys/netgraph/ng_device.c (revision 47095f775f9b9923350a5ab0796a4e08e2c62151)
1a8353960SJulian Elischer /*
2a8353960SJulian Elischer  * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
381755e6eSGleb Smirnoff  * Copyright (c) 2004 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 */
66547d3473SGleb Smirnoff static ng_constructor_t	ng_device_constructor;
67a8353960SJulian Elischer static ng_rcvmsg_t	ng_device_rcvmsg;
68547d3473SGleb Smirnoff static ng_shutdown_t	ng_device_shutdown;
69a8353960SJulian Elischer static ng_newhook_t	ng_device_newhook;
70a8353960SJulian Elischer static ng_rcvdata_t	ng_device_rcvdata;
71a8353960SJulian Elischer static ng_disconnect_t	ng_device_disconnect;
72a8353960SJulian Elischer 
73a8353960SJulian Elischer /* Netgraph type */
74547d3473SGleb Smirnoff static struct ng_type ngd_typestruct = {
75f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
76f8aae777SJulian Elischer 	.name =		NG_DEVICE_NODE_TYPE,
77547d3473SGleb Smirnoff 	.constructor =	ng_device_constructor,
78f8aae777SJulian Elischer 	.rcvmsg	=	ng_device_rcvmsg,
79547d3473SGleb Smirnoff 	.shutdown = 	ng_device_shutdown,
80f8aae777SJulian Elischer 	.newhook =	ng_device_newhook,
81f8aae777SJulian Elischer 	.rcvdata =	ng_device_rcvdata,
82f8aae777SJulian Elischer 	.disconnect =	ng_device_disconnect,
83a8353960SJulian Elischer };
84547d3473SGleb Smirnoff NETGRAPH_INIT(device, &ngd_typestruct);
85a8353960SJulian Elischer 
86547d3473SGleb Smirnoff /* per node data */
87547d3473SGleb Smirnoff struct ngd_private {
88547d3473SGleb Smirnoff 	struct	ifqueue	readq;
89547d3473SGleb Smirnoff 	SLIST_ENTRY(ngd_private) links;
90547d3473SGleb Smirnoff 	struct	ng_node	*node;
91547d3473SGleb Smirnoff 	struct	ng_hook	*hook;
9289c9c53dSPoul-Henning Kamp 	struct	cdev	*ngddev;
93547d3473SGleb Smirnoff 	struct	mtx	ngd_mtx;
94a8353960SJulian Elischer 	int 		unit;
95547d3473SGleb Smirnoff 	uint16_t	flags;
96547d3473SGleb Smirnoff #define	NGDF_OPEN	0x0001
97547d3473SGleb Smirnoff #define	NGDF_RWAIT	0x0002
98a8353960SJulian Elischer };
99547d3473SGleb Smirnoff typedef struct ngd_private *priv_p;
100a8353960SJulian Elischer 
101547d3473SGleb Smirnoff /* List of all active nodes and mutex to protect it */
102547d3473SGleb Smirnoff static SLIST_HEAD(, ngd_private) ngd_nodes = SLIST_HEAD_INITIALIZER(ngd_nodes);
103547d3473SGleb Smirnoff static struct mtx	ng_device_mtx;
104547d3473SGleb Smirnoff MTX_SYSINIT(ng_device, &ng_device_mtx, "ng_device", MTX_DEF);
105a8353960SJulian Elischer 
106a8353960SJulian Elischer /* Maximum number of NGD devices */
107a8353960SJulian Elischer #define MAX_NGD	25	/* should be more than enough for now */
108a8353960SJulian Elischer 
109a8353960SJulian Elischer static d_close_t ngdclose;
110a8353960SJulian Elischer static d_open_t ngdopen;
111a8353960SJulian Elischer static d_read_t ngdread;
112a8353960SJulian Elischer static d_write_t ngdwrite;
113547d3473SGleb Smirnoff #if 0
114a8353960SJulian Elischer static d_ioctl_t ngdioctl;
115547d3473SGleb Smirnoff #endif
116a8353960SJulian Elischer static d_poll_t ngdpoll;
117a8353960SJulian Elischer 
118a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = {
119dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
1207ac40f5fSPoul-Henning Kamp 	.d_open =	ngdopen,
1217ac40f5fSPoul-Henning Kamp 	.d_close =	ngdclose,
1227ac40f5fSPoul-Henning Kamp 	.d_read =	ngdread,
1237ac40f5fSPoul-Henning Kamp 	.d_write =	ngdwrite,
124547d3473SGleb Smirnoff #if 0
1257ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ngdioctl,
126547d3473SGleb Smirnoff #endif
1277ac40f5fSPoul-Henning Kamp 	.d_poll =	ngdpoll,
128547d3473SGleb Smirnoff 	.d_name =	NG_DEVICE_DEVNAME,
129a8353960SJulian Elischer };
130a8353960SJulian Elischer 
131547d3473SGleb Smirnoff /* Helper functions */
132547d3473SGleb Smirnoff static int get_free_unit(void);
133547d3473SGleb Smirnoff 
134547d3473SGleb Smirnoff /******************************************************************************
135547d3473SGleb Smirnoff  *  Netgraph methods
136547d3473SGleb Smirnoff  ******************************************************************************/
137547d3473SGleb Smirnoff 
138a8353960SJulian Elischer /*
139547d3473SGleb Smirnoff  * create new node
140a8353960SJulian Elischer  */
141a8353960SJulian Elischer static int
142547d3473SGleb Smirnoff ng_device_constructor(node_p node)
143a8353960SJulian Elischer {
144547d3473SGleb Smirnoff 	priv_p	priv;
145a8353960SJulian Elischer 
146f2b9562cSGleb Smirnoff 	DBG;
147a8353960SJulian Elischer 
148547d3473SGleb Smirnoff 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
149547d3473SGleb Smirnoff 	if (priv == NULL)
150547d3473SGleb Smirnoff 		return (ENOMEM);
151a8353960SJulian Elischer 
152547d3473SGleb Smirnoff 	mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
153547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
154a8353960SJulian Elischer 
155547d3473SGleb Smirnoff 	mtx_lock(&ng_device_mtx);
156a8353960SJulian Elischer 
157547d3473SGleb Smirnoff 	priv->unit = get_free_unit();
158547d3473SGleb Smirnoff 	if(priv->unit < 0) {
159547d3473SGleb Smirnoff 		printf("%s: No free unit found by get_free_unit(), "
160547d3473SGleb Smirnoff 				"increase MAX_NGD\n",__func__);
161547d3473SGleb Smirnoff 		mtx_unlock(&ng_device_mtx);
162547d3473SGleb Smirnoff 		mtx_destroy(&priv->ngd_mtx);
163547d3473SGleb Smirnoff 		FREE(priv, M_NETGRAPH);
164547d3473SGleb Smirnoff 		return(EINVAL);
165a8353960SJulian Elischer 	}
166a8353960SJulian Elischer 
167547d3473SGleb Smirnoff 	priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT,
168547d3473SGleb Smirnoff 	    GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
169547d3473SGleb Smirnoff 	if(priv->ngddev == NULL) {
170547d3473SGleb Smirnoff 		printf("%s(): make_dev() failed\n",__func__);
171547d3473SGleb Smirnoff 		mtx_unlock(&ng_device_mtx);
172547d3473SGleb Smirnoff 		mtx_destroy(&priv->ngd_mtx);
173547d3473SGleb Smirnoff 		FREE(priv, M_NETGRAPH);
174547d3473SGleb Smirnoff 		return(EINVAL);
175a8353960SJulian Elischer 	}
176a8353960SJulian Elischer 
177547d3473SGleb Smirnoff 	SLIST_INSERT_HEAD(&ngd_nodes, priv, links);
178a8353960SJulian Elischer 
179547d3473SGleb Smirnoff 	mtx_unlock(&ng_device_mtx);
180a8353960SJulian Elischer 
181547d3473SGleb Smirnoff 	mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
182547d3473SGleb Smirnoff 	IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
183a8353960SJulian Elischer 
184547d3473SGleb Smirnoff 	/* Link everything together */
185547d3473SGleb Smirnoff 	NG_NODE_SET_PRIVATE(node, priv);
186547d3473SGleb Smirnoff 	priv->node = node;
187547d3473SGleb Smirnoff 	priv->ngddev->si_drv1 = priv;
188a8353960SJulian Elischer 
189547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
190a8353960SJulian Elischer 
191a8353960SJulian Elischer 	return(0);
192a8353960SJulian Elischer }
193a8353960SJulian Elischer 
194a8353960SJulian Elischer /*
195547d3473SGleb Smirnoff  * Process control message.
196a8353960SJulian Elischer  */
197a8353960SJulian Elischer 
198a8353960SJulian Elischer static int
199a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
200a8353960SJulian Elischer {
201547d3473SGleb Smirnoff 	const priv_p priv = NG_NODE_PRIVATE(node);
202a8353960SJulian Elischer 	struct ng_mesg *msg;
203547d3473SGleb Smirnoff 	struct ng_mesg *resp = NULL;
204a8353960SJulian Elischer 	int error = 0;
205a8353960SJulian Elischer 
206a8353960SJulian Elischer 	NGI_GET_MSG(item, msg);
207a8353960SJulian Elischer 
208547d3473SGleb Smirnoff 	if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
209547d3473SGleb Smirnoff 		switch (msg->header.cmd) {
210547d3473SGleb Smirnoff 		case NGM_DEVICE_GET_DEVNAME:
211547d3473SGleb Smirnoff 			/* XXX: Fix when NGD_MAX us bigger */
212547d3473SGleb Smirnoff 			NG_MKRESPONSE(resp, msg,
213547d3473SGleb Smirnoff 			    strlen(NG_DEVICE_DEVNAME) + 3, M_NOWAIT);
214a8353960SJulian Elischer 
215547d3473SGleb Smirnoff 			if (resp == NULL)
216547d3473SGleb Smirnoff 				ERROUT(ENOMEM);
217547d3473SGleb Smirnoff 
218547d3473SGleb Smirnoff 			strlcpy((char *)resp->data, priv->ngddev->si_name,
219547d3473SGleb Smirnoff 			    strlen(priv->ngddev->si_name) + 1);
220547d3473SGleb Smirnoff 			break;
221547d3473SGleb Smirnoff 
222547d3473SGleb Smirnoff 		default:
223547d3473SGleb Smirnoff 			error = EINVAL;
224547d3473SGleb Smirnoff 			break;
225547d3473SGleb Smirnoff 		}
226547d3473SGleb Smirnoff 	} else
227547d3473SGleb Smirnoff 		error = EINVAL;
228547d3473SGleb Smirnoff 
229547d3473SGleb Smirnoff done:
230547d3473SGleb Smirnoff 	NG_RESPOND_MSG(error, node, item, resp);
231547d3473SGleb Smirnoff 	NG_FREE_MSG(msg);
232a8353960SJulian Elischer 	return (error);
233a8353960SJulian Elischer }
234a8353960SJulian Elischer 
235a8353960SJulian Elischer /*
236547d3473SGleb Smirnoff  * Accept incoming hook. We support only one hook per node.
237a8353960SJulian Elischer  */
238a8353960SJulian Elischer static int
239a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name)
240a8353960SJulian Elischer {
241547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(node);
242a8353960SJulian Elischer 
243f2b9562cSGleb Smirnoff 	DBG;
244a8353960SJulian Elischer 
245547d3473SGleb Smirnoff 	/* We have only one hook per node */
246547d3473SGleb Smirnoff 	if (priv->hook != NULL)
247547d3473SGleb Smirnoff 		return (EISCONN);
248a8353960SJulian Elischer 
249547d3473SGleb Smirnoff 	priv->hook = hook;
250a8353960SJulian Elischer 
251a8353960SJulian Elischer 	return(0);
252a8353960SJulian Elischer }
253a8353960SJulian Elischer 
254a8353960SJulian Elischer /*
255547d3473SGleb Smirnoff  * Receive data from hook, write it to device.
256a8353960SJulian Elischer  */
257a8353960SJulian Elischer static int
258a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item)
259a8353960SJulian Elischer {
260547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
261a8353960SJulian Elischer 	struct mbuf *m;
262a8353960SJulian Elischer 
263f2b9562cSGleb Smirnoff 	DBG;
264a8353960SJulian Elischer 
265a8353960SJulian Elischer 	NGI_GET_M(item, m);
266a8353960SJulian Elischer 	NG_FREE_ITEM(item);
267a8353960SJulian Elischer 
268547d3473SGleb Smirnoff 	IF_LOCK(&priv->readq);
269547d3473SGleb Smirnoff 	if (_IF_QFULL(&priv->readq)) {
270547d3473SGleb Smirnoff 		_IF_DROP(&priv->readq);
271547d3473SGleb Smirnoff 		IF_UNLOCK(&priv->readq);
272c1eec6c5SGleb Smirnoff 		NG_FREE_M(m);
273547d3473SGleb Smirnoff 		return (ENOBUFS);
274547d3473SGleb Smirnoff 	}
275547d3473SGleb Smirnoff 
276547d3473SGleb Smirnoff 	_IF_ENQUEUE(&priv->readq, m);
277547d3473SGleb Smirnoff 	IF_UNLOCK(&priv->readq);
278547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
279547d3473SGleb Smirnoff 	if (priv->flags & NGDF_RWAIT) {
280547d3473SGleb Smirnoff 		priv->flags &= ~NGDF_RWAIT;
281547d3473SGleb Smirnoff 		wakeup(priv);
282547d3473SGleb Smirnoff 	}
283547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
284547d3473SGleb Smirnoff 
285547d3473SGleb Smirnoff 	return(0);
286a8353960SJulian Elischer }
287a8353960SJulian Elischer 
288a8353960SJulian Elischer /*
289547d3473SGleb Smirnoff  * Removal of the hook destroys the node.
290a8353960SJulian Elischer  */
291a8353960SJulian Elischer static int
292a8353960SJulian Elischer ng_device_disconnect(hook_p hook)
293a8353960SJulian Elischer {
294547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
295a8353960SJulian Elischer 
296f2b9562cSGleb Smirnoff 	DBG;
297a8353960SJulian Elischer 
298547d3473SGleb Smirnoff 	destroy_dev(priv->ngddev);
299547d3473SGleb Smirnoff 	mtx_destroy(&priv->ngd_mtx);
300c1eec6c5SGleb Smirnoff 
301547d3473SGleb Smirnoff 	mtx_lock(&ng_device_mtx);
302547d3473SGleb Smirnoff 	SLIST_REMOVE(&ngd_nodes, priv, ngd_private, links);
303547d3473SGleb Smirnoff 	mtx_unlock(&ng_device_mtx);
304a8353960SJulian Elischer 
305547d3473SGleb Smirnoff 	IF_DRAIN(&priv->readq);
306547d3473SGleb Smirnoff 	mtx_destroy(&(priv)->readq.ifq_mtx);
307a8353960SJulian Elischer 
308547d3473SGleb Smirnoff 	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 	SLIST_FOREACH(tmp,&sc->head,links) {
385a8353960SJulian Elischer 		if(tmp->ngddev == dev) {
386a8353960SJulian Elischer 			connection = tmp;
387a8353960SJulian Elischer 		}
388a8353960SJulian Elischer 	}
389a8353960SJulian Elischer 	if(connection == NULL) {
390a8353960SJulian Elischer 		printf("%s(): connection is still NULL, no dev found\n",__func__);
391a8353960SJulian Elischer 		return(-1);
392a8353960SJulian Elischer 	}
393a8353960SJulian Elischer 
394a8353960SJulian Elischer 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
395a8353960SJulian Elischer 			M_NOWAIT);
396a8353960SJulian Elischer 	if (msg == NULL) {
397a8353960SJulian Elischer 		printf("%s(): msg == NULL\n",__func__);
398a8353960SJulian Elischer 		goto nomsg;
399a8353960SJulian Elischer 	}
400a8353960SJulian Elischer 
401a8353960SJulian Elischer 	/* pass the ioctl data into the ->data area */
402a8353960SJulian Elischer 	datap = (struct ngd_param_s *)msg->data;
403a8353960SJulian Elischer 	datap->p = addr;
404a8353960SJulian Elischer 
405b3e3ef98SGleb Smirnoff 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
406a8353960SJulian Elischer 	if(error)
407a8353960SJulian Elischer 		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
408a8353960SJulian Elischer 
409a8353960SJulian Elischer nomsg:
410a8353960SJulian Elischer 
411a8353960SJulian Elischer 	return(0);
412a8353960SJulian Elischer }
413547d3473SGleb Smirnoff #endif /* if 0 */
414a8353960SJulian Elischer 
415a8353960SJulian Elischer /*
416a8353960SJulian Elischer  * This function is called when a read(2) is done to our device.
417547d3473SGleb Smirnoff  * We process one mbuf from queue.
418a8353960SJulian Elischer  */
419a8353960SJulian Elischer static int
42089c9c53dSPoul-Henning Kamp ngdread(struct cdev *dev, struct uio *uio, int flag)
421a8353960SJulian Elischer {
422547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
423547d3473SGleb Smirnoff 	struct mbuf *m;
424547d3473SGleb Smirnoff 	int len, error = 0;
425a8353960SJulian Elischer 
426f2b9562cSGleb Smirnoff 	DBG;
427a8353960SJulian Elischer 
428547d3473SGleb Smirnoff 	/* get an mbuf */
429547d3473SGleb Smirnoff 	do {
430547d3473SGleb Smirnoff 		IF_DEQUEUE(&priv->readq, m);
431547d3473SGleb Smirnoff 		if (m == NULL) {
432547d3473SGleb Smirnoff 			if (flag & IO_NDELAY)
433547d3473SGleb Smirnoff 				return (EWOULDBLOCK);
434547d3473SGleb Smirnoff 			mtx_lock(&priv->ngd_mtx);
435547d3473SGleb Smirnoff 			priv->flags |= NGDF_RWAIT;
43647095f77SRoman Kurakin 			if ((error = msleep(priv, &priv->ngd_mtx,
43747095f77SRoman Kurakin 			    PDROP | PCATCH | (PZERO + 1),
438547d3473SGleb Smirnoff 			    "ngdread", 0)) != 0)
439547d3473SGleb Smirnoff 				return (error);
440a8353960SJulian Elischer 		}
441547d3473SGleb Smirnoff 	} while (m == NULL);
442547d3473SGleb Smirnoff 
443547d3473SGleb Smirnoff 	while (m && uio->uio_resid > 0 && error == 0) {
444547d3473SGleb Smirnoff 		len = MIN(uio->uio_resid, m->m_len);
445547d3473SGleb Smirnoff 		if (len != 0)
446547d3473SGleb Smirnoff 			error = uiomove(mtod(m, void *), len, uio);
447547d3473SGleb Smirnoff 		m = m_free(m);
448a8353960SJulian Elischer 	}
449a8353960SJulian Elischer 
450547d3473SGleb Smirnoff 	if (m)
451547d3473SGleb Smirnoff 		m_freem(m);
452a8353960SJulian Elischer 
453547d3473SGleb Smirnoff 	return (error);
454a8353960SJulian Elischer }
455a8353960SJulian Elischer 
456a8353960SJulian Elischer 
457a8353960SJulian Elischer /*
458a8353960SJulian Elischer  * This function is called when our device is written to.
459547d3473SGleb Smirnoff  * We read the data from userland into mbuf chain and pass it to the remote hook.
460a8353960SJulian Elischer  *
461a8353960SJulian Elischer  */
462a8353960SJulian Elischer static int
46389c9c53dSPoul-Henning Kamp ngdwrite(struct cdev *dev, struct uio *uio, int flag)
464a8353960SJulian Elischer {
465547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
466a8353960SJulian Elischer 	struct mbuf *m;
467547d3473SGleb Smirnoff 	int error = 0;
468a8353960SJulian Elischer 
469f2b9562cSGleb Smirnoff 	DBG;
470a8353960SJulian Elischer 
471547d3473SGleb Smirnoff 	if (uio->uio_resid == 0)
472a8353960SJulian Elischer 		return (0);
473a8353960SJulian Elischer 
474547d3473SGleb Smirnoff 	if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
475547d3473SGleb Smirnoff 		return (EIO);
476a8353960SJulian Elischer 
477547d3473SGleb Smirnoff 	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL)
478547d3473SGleb Smirnoff 		return (ENOBUFS);
479547d3473SGleb Smirnoff 
480547d3473SGleb Smirnoff 	NG_SEND_DATA_ONLY(error, priv->hook, m);
481547d3473SGleb Smirnoff 
482547d3473SGleb Smirnoff 	return (error);
483a8353960SJulian Elischer }
484a8353960SJulian Elischer 
485a8353960SJulian Elischer /*
486a8353960SJulian Elischer  * we are being polled/selected
487a8353960SJulian Elischer  * check if there is data available for read
488a8353960SJulian Elischer  */
489a8353960SJulian Elischer static int
49089c9c53dSPoul-Henning Kamp ngdpoll(struct cdev *dev, int events, struct thread *td)
491a8353960SJulian Elischer {
492547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
493a8353960SJulian Elischer 	int revents = 0;
494a8353960SJulian Elischer 
495547d3473SGleb Smirnoff 	if (events & (POLLIN | POLLRDNORM) &&
496547d3473SGleb Smirnoff 	    !IFQ_IS_EMPTY(&priv->readq))
497a8353960SJulian Elischer 		revents |= events & (POLLIN | POLLRDNORM);
498a8353960SJulian Elischer 
499a8353960SJulian Elischer 	return (revents);
500a8353960SJulian Elischer }
501547d3473SGleb Smirnoff 
502547d3473SGleb Smirnoff /******************************************************************************
503547d3473SGleb Smirnoff  *  Helper subroutines
504547d3473SGleb Smirnoff  ******************************************************************************/
505547d3473SGleb Smirnoff 
506547d3473SGleb Smirnoff static int
507547d3473SGleb Smirnoff get_free_unit()
508547d3473SGleb Smirnoff {
509547d3473SGleb Smirnoff 	struct ngd_private *priv = NULL;
510547d3473SGleb Smirnoff 	int n = 0;
511547d3473SGleb Smirnoff 	int unit = -1;
512547d3473SGleb Smirnoff 
513f2b9562cSGleb Smirnoff 	DBG;
514547d3473SGleb Smirnoff 
515547d3473SGleb Smirnoff 	mtx_assert(&ng_device_mtx, MA_OWNED);
516547d3473SGleb Smirnoff 
517547d3473SGleb Smirnoff 	/* When there is no list yet, the first device unit is always 0. */
518547d3473SGleb Smirnoff 	if SLIST_EMPTY(&ngd_nodes)
519547d3473SGleb Smirnoff 		return(0);
520547d3473SGleb Smirnoff 
521547d3473SGleb Smirnoff 	/* Just do a brute force loop to find the first free unit that is
522547d3473SGleb Smirnoff 	 * smaller than MAX_NGD.
523547d3473SGleb Smirnoff 	 * Set MAX_NGD to a large value, doesn't impact performance.
524547d3473SGleb Smirnoff 	 */
525547d3473SGleb Smirnoff 	for(n = 0; n<MAX_NGD && unit == -1; n++) {
526547d3473SGleb Smirnoff 		SLIST_FOREACH(priv, &ngd_nodes, links) {
527547d3473SGleb Smirnoff 
528547d3473SGleb Smirnoff 			if(priv->unit == n) {
529547d3473SGleb Smirnoff 				unit = -1;
530547d3473SGleb Smirnoff 				break;
531547d3473SGleb Smirnoff 			}
532547d3473SGleb Smirnoff 			unit = n;
533547d3473SGleb Smirnoff 		}
534547d3473SGleb Smirnoff 	}
535547d3473SGleb Smirnoff 
536547d3473SGleb Smirnoff 	return (unit);
537547d3473SGleb Smirnoff }
538