xref: /freebsd/sys/netgraph/ng_device.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1c398230bSWarner Losh /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4a8353960SJulian Elischer  * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
55cdd064dSGleb Smirnoff  * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
6a8353960SJulian Elischer  *
7a8353960SJulian Elischer  * Redistribution and use in source and binary forms, with or without
8a8353960SJulian Elischer  * modification, are permitted provided that the following conditions
9a8353960SJulian Elischer  * are met:
10a8353960SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
11a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
12a8353960SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
13a8353960SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
14a8353960SJulian Elischer  *    documentation and/or other materials provided with the distribution.
15a8353960SJulian Elischer  *
16a8353960SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17a8353960SJulian Elischer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18a8353960SJulian Elischer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19a8353960SJulian Elischer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20a8353960SJulian Elischer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21a8353960SJulian Elischer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22a8353960SJulian Elischer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23a8353960SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24a8353960SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25a8353960SJulian Elischer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26a8353960SJulian Elischer  *
27a8353960SJulian Elischer  * Netgraph "device" node
28a8353960SJulian Elischer  *
29a8353960SJulian Elischer  * This node presents a /dev/ngd%d device that interfaces to an other
30a8353960SJulian Elischer  * netgraph node.
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>
47f71291a6SGleb Smirnoff #include <sys/proc.h>
48f71291a6SGleb Smirnoff #include <sys/epoch.h>
49b3e3ef98SGleb Smirnoff #include <sys/queue.h>
50547d3473SGleb Smirnoff #include <sys/socket.h>
5144aae623SIan Lepore #include <sys/syslog.h>
52b3e3ef98SGleb Smirnoff #include <sys/systm.h>
53b3e3ef98SGleb Smirnoff #include <sys/uio.h>
54547d3473SGleb Smirnoff #include <sys/vnode.h>
55547d3473SGleb Smirnoff 
5644aae623SIan Lepore #include <net/ethernet.h>
57547d3473SGleb Smirnoff #include <net/if.h>
58547d3473SGleb Smirnoff #include <net/if_var.h>
59547d3473SGleb Smirnoff #include <netinet/in.h>
60547d3473SGleb Smirnoff #include <netinet/in_systm.h>
61547d3473SGleb Smirnoff #include <netinet/ip.h>
62a8353960SJulian Elischer 
63a8353960SJulian Elischer #include <netgraph/ng_message.h>
64a8353960SJulian Elischer #include <netgraph/netgraph.h>
65b3e3ef98SGleb Smirnoff #include <netgraph/ng_device.h>
6644aae623SIan Lepore #include <netgraph/ng_parse.h>
67a8353960SJulian Elischer 
68c1eec6c5SGleb Smirnoff #define	ERROUT(x) do { error = (x); goto done; } while (0)
69c1eec6c5SGleb Smirnoff 
70a8353960SJulian Elischer /* Netgraph methods */
7130aabc9aSRuslan Ermilov static int		ng_device_mod_event(module_t, int, void *);
72547d3473SGleb Smirnoff static ng_constructor_t	ng_device_constructor;
73a8353960SJulian Elischer static ng_rcvmsg_t	ng_device_rcvmsg;
74547d3473SGleb Smirnoff static ng_shutdown_t	ng_device_shutdown;
75a8353960SJulian Elischer static ng_newhook_t	ng_device_newhook;
76a8353960SJulian Elischer static ng_rcvdata_t	ng_device_rcvdata;
77a8353960SJulian Elischer static ng_disconnect_t	ng_device_disconnect;
78a8353960SJulian Elischer 
7944aae623SIan Lepore /* List of commands and how to convert arguments to/from ASCII. */
8044aae623SIan Lepore static const struct ng_cmdlist ng_device_cmds[] = {
8144aae623SIan Lepore 	{
8244aae623SIan Lepore 	  NGM_DEVICE_COOKIE,
8344aae623SIan Lepore 	  NGM_DEVICE_GET_DEVNAME,
8444aae623SIan Lepore 	  "getdevname",
8544aae623SIan Lepore 	  NULL,
8644aae623SIan Lepore 	  &ng_parse_string_type
8744aae623SIan Lepore 	},
8844aae623SIan Lepore 	{
8944aae623SIan Lepore 	  NGM_DEVICE_COOKIE,
9044aae623SIan Lepore 	  NGM_DEVICE_ETHERALIGN,
9144aae623SIan Lepore 	  "etheralign",
9244aae623SIan Lepore 	  NULL,
9344aae623SIan Lepore 	  NULL
9444aae623SIan Lepore 	},
9544aae623SIan Lepore 	{ 0 }
9644aae623SIan Lepore };
9744aae623SIan Lepore 
98a8353960SJulian Elischer /* Netgraph type */
99547d3473SGleb Smirnoff static struct ng_type ngd_typestruct = {
100f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
101f8aae777SJulian Elischer 	.name =		NG_DEVICE_NODE_TYPE,
10230aabc9aSRuslan Ermilov 	.mod_event =	ng_device_mod_event,
103547d3473SGleb Smirnoff 	.constructor =	ng_device_constructor,
104f8aae777SJulian Elischer 	.rcvmsg	=	ng_device_rcvmsg,
105547d3473SGleb Smirnoff 	.shutdown = 	ng_device_shutdown,
106f8aae777SJulian Elischer 	.newhook =	ng_device_newhook,
107f8aae777SJulian Elischer 	.rcvdata =	ng_device_rcvdata,
108f8aae777SJulian Elischer 	.disconnect =	ng_device_disconnect,
10944aae623SIan Lepore 	.cmdlist =	ng_device_cmds,
110a8353960SJulian Elischer };
111547d3473SGleb Smirnoff NETGRAPH_INIT(device, &ngd_typestruct);
112a8353960SJulian Elischer 
113547d3473SGleb Smirnoff /* per node data */
114547d3473SGleb Smirnoff struct ngd_private {
115547d3473SGleb Smirnoff 	struct	ifqueue	readq;
116547d3473SGleb Smirnoff 	struct	ng_node	*node;
117547d3473SGleb Smirnoff 	struct	ng_hook	*hook;
11889c9c53dSPoul-Henning Kamp 	struct	cdev	*ngddev;
119547d3473SGleb Smirnoff 	struct	mtx	ngd_mtx;
120a8353960SJulian Elischer 	int 		unit;
12144aae623SIan Lepore 	int		ether_align;
122547d3473SGleb Smirnoff 	uint16_t	flags;
123547d3473SGleb Smirnoff #define	NGDF_OPEN	0x0001
124547d3473SGleb Smirnoff #define	NGDF_RWAIT	0x0002
125a8353960SJulian Elischer };
126547d3473SGleb Smirnoff typedef struct ngd_private *priv_p;
127a8353960SJulian Elischer 
1285cdd064dSGleb Smirnoff /* unit number allocator entity */
1295cdd064dSGleb Smirnoff static struct unrhdr *ngd_unit;
130a8353960SJulian Elischer 
131a8353960SJulian Elischer /* Maximum number of NGD devices */
1325cdd064dSGleb Smirnoff #define MAX_NGD	999
133a8353960SJulian Elischer 
134a8353960SJulian Elischer static d_close_t ngdclose;
135a8353960SJulian Elischer static d_open_t ngdopen;
136a8353960SJulian Elischer static d_read_t ngdread;
137a8353960SJulian Elischer static d_write_t ngdwrite;
138547d3473SGleb Smirnoff #if 0
139a8353960SJulian Elischer static d_ioctl_t ngdioctl;
140547d3473SGleb Smirnoff #endif
141a8353960SJulian Elischer static d_poll_t ngdpoll;
142a8353960SJulian Elischer 
143a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = {
144dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
1457ac40f5fSPoul-Henning Kamp 	.d_open =	ngdopen,
1467ac40f5fSPoul-Henning Kamp 	.d_close =	ngdclose,
1477ac40f5fSPoul-Henning Kamp 	.d_read =	ngdread,
1487ac40f5fSPoul-Henning Kamp 	.d_write =	ngdwrite,
149547d3473SGleb Smirnoff #if 0
1507ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ngdioctl,
151547d3473SGleb Smirnoff #endif
1527ac40f5fSPoul-Henning Kamp 	.d_poll =	ngdpoll,
153547d3473SGleb Smirnoff 	.d_name =	NG_DEVICE_DEVNAME,
154a8353960SJulian Elischer };
155a8353960SJulian Elischer 
156547d3473SGleb Smirnoff /******************************************************************************
157547d3473SGleb Smirnoff  *  Netgraph methods
158547d3473SGleb Smirnoff  ******************************************************************************/
159547d3473SGleb Smirnoff 
160a8353960SJulian Elischer /*
1615cdd064dSGleb Smirnoff  * Handle loading and unloading for this node type.
1625cdd064dSGleb Smirnoff  */
1635cdd064dSGleb Smirnoff static int
ng_device_mod_event(module_t mod,int event,void * data)1645cdd064dSGleb Smirnoff ng_device_mod_event(module_t mod, int event, void *data)
1655cdd064dSGleb Smirnoff {
1665cdd064dSGleb Smirnoff 	int error = 0;
1675cdd064dSGleb Smirnoff 
1685cdd064dSGleb Smirnoff 	switch (event) {
1695cdd064dSGleb Smirnoff 	case MOD_LOAD:
1705cdd064dSGleb Smirnoff 		ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
1715cdd064dSGleb Smirnoff 		break;
1725cdd064dSGleb Smirnoff 	case MOD_UNLOAD:
1735cdd064dSGleb Smirnoff 		delete_unrhdr(ngd_unit);
1745cdd064dSGleb Smirnoff 		break;
1755cdd064dSGleb Smirnoff 	default:
1765cdd064dSGleb Smirnoff 		error = EOPNOTSUPP;
1775cdd064dSGleb Smirnoff 		break;
1785cdd064dSGleb Smirnoff 	}
1795cdd064dSGleb Smirnoff 	return (error);
1805cdd064dSGleb Smirnoff }
1815cdd064dSGleb Smirnoff 
1825cdd064dSGleb Smirnoff /*
183547d3473SGleb Smirnoff  * create new node
184a8353960SJulian Elischer  */
185a8353960SJulian Elischer static int
ng_device_constructor(node_p node)186547d3473SGleb Smirnoff ng_device_constructor(node_p node)
187a8353960SJulian Elischer {
188547d3473SGleb Smirnoff 	priv_p	priv;
189a8353960SJulian Elischer 
190f2b9562cSGleb Smirnoff 	DBG;
191a8353960SJulian Elischer 
192674d86bfSGleb Smirnoff 	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
193a8353960SJulian Elischer 
1945cdd064dSGleb Smirnoff 	/* Allocate unit number */
1955cdd064dSGleb Smirnoff 	priv->unit = alloc_unr(ngd_unit);
196a8353960SJulian Elischer 
197843cfd5aSGleb Smirnoff 	/* Initialize mutexes and queue */
198843cfd5aSGleb Smirnoff 	mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
199547d3473SGleb Smirnoff 	mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
200547d3473SGleb Smirnoff 	IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
201a8353960SJulian Elischer 
202547d3473SGleb Smirnoff 	/* Link everything together */
203547d3473SGleb Smirnoff 	NG_NODE_SET_PRIVATE(node, priv);
204547d3473SGleb Smirnoff 	priv->node = node;
205a8353960SJulian Elischer 
206d3ce8327SEd Schouten 	priv->ngddev = make_dev(&ngd_cdevsw, priv->unit, UID_ROOT,
207843cfd5aSGleb Smirnoff 	    GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
208843cfd5aSGleb Smirnoff 	if(priv->ngddev == NULL) {
209843cfd5aSGleb Smirnoff 		printf("%s(): make_dev() failed\n",__func__);
210843cfd5aSGleb Smirnoff 		mtx_destroy(&priv->ngd_mtx);
211843cfd5aSGleb Smirnoff 		mtx_destroy(&priv->readq.ifq_mtx);
2125cdd064dSGleb Smirnoff 		free_unr(ngd_unit, priv->unit);
2131ede983cSDag-Erling Smørgrav 		free(priv, M_NETGRAPH);
214843cfd5aSGleb Smirnoff 		return(EINVAL);
215843cfd5aSGleb Smirnoff 	}
216843cfd5aSGleb Smirnoff 	/* XXX: race here? */
217843cfd5aSGleb Smirnoff 	priv->ngddev->si_drv1 = priv;
218a8353960SJulian Elischer 
21944aae623SIan Lepore 	/* Give this node the same name as the device (if possible). */
22044aae623SIan Lepore 	if (ng_name_node(node, devtoname(priv->ngddev)) != 0)
22144aae623SIan Lepore 		log(LOG_WARNING, "%s: can't acquire netgraph name\n",
22244aae623SIan Lepore 		    devtoname(priv->ngddev));
22344aae623SIan Lepore 
224a8353960SJulian Elischer 	return(0);
225a8353960SJulian Elischer }
226a8353960SJulian Elischer 
227a8353960SJulian Elischer /*
228547d3473SGleb Smirnoff  * Process control message.
229a8353960SJulian Elischer  */
230a8353960SJulian Elischer 
231a8353960SJulian Elischer static int
ng_device_rcvmsg(node_p node,item_p item,hook_p lasthook)232a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
233a8353960SJulian Elischer {
234547d3473SGleb Smirnoff 	const priv_p priv = NG_NODE_PRIVATE(node);
235a8353960SJulian Elischer 	struct ng_mesg *msg;
236547d3473SGleb Smirnoff 	struct ng_mesg *resp = NULL;
2377870adb6SEd Schouten 	const char *dn;
238a8353960SJulian Elischer 	int error = 0;
239a8353960SJulian Elischer 
240a8353960SJulian Elischer 	NGI_GET_MSG(item, msg);
241a8353960SJulian Elischer 
242547d3473SGleb Smirnoff 	if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
243547d3473SGleb Smirnoff 		switch (msg->header.cmd) {
244547d3473SGleb Smirnoff 		case NGM_DEVICE_GET_DEVNAME:
2455cdd064dSGleb Smirnoff 			/* XXX: Fix when MAX_NGD us bigger */
246547d3473SGleb Smirnoff 			NG_MKRESPONSE(resp, msg,
2475cdd064dSGleb Smirnoff 			    strlen(NG_DEVICE_DEVNAME) + 4, M_NOWAIT);
248a8353960SJulian Elischer 
249547d3473SGleb Smirnoff 			if (resp == NULL)
250547d3473SGleb Smirnoff 				ERROUT(ENOMEM);
251547d3473SGleb Smirnoff 
2527870adb6SEd Schouten 			dn = devtoname(priv->ngddev);
2537870adb6SEd Schouten 			strlcpy((char *)resp->data, dn, strlen(dn) + 1);
254547d3473SGleb Smirnoff 			break;
255547d3473SGleb Smirnoff 
25644aae623SIan Lepore 		case NGM_DEVICE_ETHERALIGN:
25744aae623SIan Lepore 			/* Use ETHER_ALIGN on arches that require it. */
25844aae623SIan Lepore #ifndef __NO_STRICT_ALIGNMENT
25944aae623SIan Lepore 			priv->ether_align = ETHER_ALIGN;
26044aae623SIan Lepore #endif
26144aae623SIan Lepore 			break;
26244aae623SIan Lepore 
263547d3473SGleb Smirnoff 		default:
264547d3473SGleb Smirnoff 			error = EINVAL;
265547d3473SGleb Smirnoff 			break;
266547d3473SGleb Smirnoff 		}
267547d3473SGleb Smirnoff 	} else
268547d3473SGleb Smirnoff 		error = EINVAL;
269547d3473SGleb Smirnoff 
270547d3473SGleb Smirnoff done:
271547d3473SGleb Smirnoff 	NG_RESPOND_MSG(error, node, item, resp);
272547d3473SGleb Smirnoff 	NG_FREE_MSG(msg);
273a8353960SJulian Elischer 	return (error);
274a8353960SJulian Elischer }
275a8353960SJulian Elischer 
276a8353960SJulian Elischer /*
277547d3473SGleb Smirnoff  * Accept incoming hook. We support only one hook per node.
278a8353960SJulian Elischer  */
279a8353960SJulian Elischer static int
ng_device_newhook(node_p node,hook_p hook,const char * name)280a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name)
281a8353960SJulian Elischer {
282547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(node);
283a8353960SJulian Elischer 
284f2b9562cSGleb Smirnoff 	DBG;
285a8353960SJulian Elischer 
286547d3473SGleb Smirnoff 	/* We have only one hook per node */
287547d3473SGleb Smirnoff 	if (priv->hook != NULL)
288547d3473SGleb Smirnoff 		return (EISCONN);
289a8353960SJulian Elischer 
290547d3473SGleb Smirnoff 	priv->hook = hook;
291a8353960SJulian Elischer 
292a8353960SJulian Elischer 	return(0);
293a8353960SJulian Elischer }
294a8353960SJulian Elischer 
295a8353960SJulian Elischer /*
296547d3473SGleb Smirnoff  * Receive data from hook, write it to device.
297a8353960SJulian Elischer  */
298a8353960SJulian Elischer static int
ng_device_rcvdata(hook_p hook,item_p item)299a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item)
300a8353960SJulian Elischer {
301547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
302a8353960SJulian Elischer 	struct mbuf *m;
303a8353960SJulian Elischer 
304f2b9562cSGleb Smirnoff 	DBG;
305a8353960SJulian Elischer 
306a8353960SJulian Elischer 	NGI_GET_M(item, m);
307a8353960SJulian Elischer 	NG_FREE_ITEM(item);
308a8353960SJulian Elischer 
309547d3473SGleb Smirnoff 	IF_LOCK(&priv->readq);
310547d3473SGleb Smirnoff 	if (_IF_QFULL(&priv->readq)) {
311547d3473SGleb Smirnoff 		IF_UNLOCK(&priv->readq);
312c1eec6c5SGleb Smirnoff 		NG_FREE_M(m);
313547d3473SGleb Smirnoff 		return (ENOBUFS);
314547d3473SGleb Smirnoff 	}
315547d3473SGleb Smirnoff 
316547d3473SGleb Smirnoff 	_IF_ENQUEUE(&priv->readq, m);
317547d3473SGleb Smirnoff 	IF_UNLOCK(&priv->readq);
318547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
319547d3473SGleb Smirnoff 	if (priv->flags & NGDF_RWAIT) {
320547d3473SGleb Smirnoff 		priv->flags &= ~NGDF_RWAIT;
321547d3473SGleb Smirnoff 		wakeup(priv);
322547d3473SGleb Smirnoff 	}
323547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
324547d3473SGleb Smirnoff 
325547d3473SGleb Smirnoff 	return(0);
326a8353960SJulian Elischer }
327a8353960SJulian Elischer 
328a8353960SJulian Elischer /*
329547d3473SGleb Smirnoff  * Removal of the hook destroys the node.
330a8353960SJulian Elischer  */
331a8353960SJulian Elischer static int
ng_device_disconnect(hook_p hook)332a8353960SJulian Elischer ng_device_disconnect(hook_p hook)
333a8353960SJulian Elischer {
334547d3473SGleb Smirnoff 	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
335a8353960SJulian Elischer 
336f2b9562cSGleb Smirnoff 	DBG;
337a8353960SJulian Elischer 
338547d3473SGleb Smirnoff 	destroy_dev(priv->ngddev);
339547d3473SGleb Smirnoff 	mtx_destroy(&priv->ngd_mtx);
340c1eec6c5SGleb Smirnoff 
341547d3473SGleb Smirnoff 	IF_DRAIN(&priv->readq);
342547d3473SGleb Smirnoff 	mtx_destroy(&(priv)->readq.ifq_mtx);
343a8353960SJulian Elischer 
3445cdd064dSGleb Smirnoff 	free_unr(ngd_unit, priv->unit);
3455cdd064dSGleb Smirnoff 
3461ede983cSDag-Erling Smørgrav 	free(priv, M_NETGRAPH);
347a8353960SJulian Elischer 
348547d3473SGleb Smirnoff 	ng_rmnode_self(NG_HOOK_NODE(hook));
349a8353960SJulian Elischer 
350a8353960SJulian Elischer 	return(0);
351a8353960SJulian Elischer }
352547d3473SGleb Smirnoff 
353547d3473SGleb Smirnoff /*
354547d3473SGleb Smirnoff  * Node shutdown. Everything is already done in disconnect method.
355547d3473SGleb Smirnoff  */
356547d3473SGleb Smirnoff static int
ng_device_shutdown(node_p node)357547d3473SGleb Smirnoff ng_device_shutdown(node_p node)
358547d3473SGleb Smirnoff {
359547d3473SGleb Smirnoff 	NG_NODE_UNREF(node);
360547d3473SGleb Smirnoff 	return (0);
361547d3473SGleb Smirnoff }
362547d3473SGleb Smirnoff 
363547d3473SGleb Smirnoff /******************************************************************************
364547d3473SGleb Smirnoff  *  Device methods
365547d3473SGleb Smirnoff  ******************************************************************************/
366547d3473SGleb Smirnoff 
367a8353960SJulian Elischer /*
368a8353960SJulian Elischer  * the device is opened
369a8353960SJulian Elischer  */
370a8353960SJulian Elischer static int
ngdopen(struct cdev * dev,int flag,int mode,struct thread * td)37189c9c53dSPoul-Henning Kamp ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
372a8353960SJulian Elischer {
373547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
374a8353960SJulian Elischer 
375f2b9562cSGleb Smirnoff 	DBG;
376f2b9562cSGleb Smirnoff 
377547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
378547d3473SGleb Smirnoff 	priv->flags |= NGDF_OPEN;
379547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
380a8353960SJulian Elischer 
381a8353960SJulian Elischer 	return(0);
382a8353960SJulian Elischer }
383a8353960SJulian Elischer 
384a8353960SJulian Elischer /*
385a8353960SJulian Elischer  * the device is closed
386a8353960SJulian Elischer  */
387a8353960SJulian Elischer static int
ngdclose(struct cdev * dev,int flag,int mode,struct thread * td)38889c9c53dSPoul-Henning Kamp ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
389a8353960SJulian Elischer {
390547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
391a8353960SJulian Elischer 
392f2b9562cSGleb Smirnoff 	DBG;
393547d3473SGleb Smirnoff 	mtx_lock(&priv->ngd_mtx);
394547d3473SGleb Smirnoff 	priv->flags &= ~NGDF_OPEN;
395547d3473SGleb Smirnoff 	mtx_unlock(&priv->ngd_mtx);
396a8353960SJulian Elischer 
397a8353960SJulian Elischer 	return(0);
398a8353960SJulian Elischer }
399a8353960SJulian Elischer 
400547d3473SGleb Smirnoff #if 0	/*
401547d3473SGleb Smirnoff 	 * The ioctl is transformed into netgraph control message.
402547d3473SGleb Smirnoff 	 * We do not process them, yet.
403547d3473SGleb Smirnoff 	 */
404a8353960SJulian Elischer /*
405a8353960SJulian Elischer  * process ioctl
406a8353960SJulian Elischer  *
407a8353960SJulian Elischer  * they are translated into netgraph messages and passed on
408a8353960SJulian Elischer  *
409a8353960SJulian Elischer  */
410a8353960SJulian Elischer static int
41189c9c53dSPoul-Henning Kamp ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
412a8353960SJulian Elischer {
413a8353960SJulian Elischer 	struct ngd_softc *sc = &ngd_softc;
414a8353960SJulian Elischer 	struct ngd_connection * connection = NULL;
415a8353960SJulian Elischer 	struct ngd_connection * tmp;
416a8353960SJulian Elischer 	int error = 0;
417a8353960SJulian Elischer 	struct ng_mesg *msg;
418a8353960SJulian Elischer 	struct ngd_param_s * datap;
419a8353960SJulian Elischer 
420f2b9562cSGleb Smirnoff 	DBG;
421a8353960SJulian Elischer 
422a8353960SJulian Elischer 	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
423a8353960SJulian Elischer 			M_NOWAIT);
424a8353960SJulian Elischer 	if (msg == NULL) {
425a8353960SJulian Elischer 		printf("%s(): msg == NULL\n",__func__);
426a8353960SJulian Elischer 		goto nomsg;
427a8353960SJulian Elischer 	}
428a8353960SJulian Elischer 
429a8353960SJulian Elischer 	/* pass the ioctl data into the ->data area */
430a8353960SJulian Elischer 	datap = (struct ngd_param_s *)msg->data;
431a8353960SJulian Elischer 	datap->p = addr;
432a8353960SJulian Elischer 
433b3e3ef98SGleb Smirnoff 	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
434a8353960SJulian Elischer 	if(error)
435a8353960SJulian Elischer 		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
436a8353960SJulian Elischer 
437a8353960SJulian Elischer nomsg:
438a8353960SJulian Elischer 
439a8353960SJulian Elischer 	return(0);
440a8353960SJulian Elischer }
441547d3473SGleb Smirnoff #endif /* if 0 */
442a8353960SJulian Elischer 
443a8353960SJulian Elischer /*
444a8353960SJulian Elischer  * This function is called when a read(2) is done to our device.
445547d3473SGleb Smirnoff  * We process one mbuf from queue.
446a8353960SJulian Elischer  */
447a8353960SJulian Elischer static int
ngdread(struct cdev * dev,struct uio * uio,int flag)44889c9c53dSPoul-Henning Kamp ngdread(struct cdev *dev, struct uio *uio, int flag)
449a8353960SJulian Elischer {
450547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
451547d3473SGleb Smirnoff 	struct mbuf *m;
452547d3473SGleb Smirnoff 	int len, error = 0;
453a8353960SJulian Elischer 
454f2b9562cSGleb Smirnoff 	DBG;
455a8353960SJulian Elischer 
456547d3473SGleb Smirnoff 	/* get an mbuf */
457547d3473SGleb Smirnoff 	do {
458547d3473SGleb Smirnoff 		IF_DEQUEUE(&priv->readq, m);
459547d3473SGleb Smirnoff 		if (m == NULL) {
460547d3473SGleb Smirnoff 			if (flag & IO_NDELAY)
461547d3473SGleb Smirnoff 				return (EWOULDBLOCK);
462547d3473SGleb Smirnoff 			mtx_lock(&priv->ngd_mtx);
463547d3473SGleb Smirnoff 			priv->flags |= NGDF_RWAIT;
46447095f77SRoman Kurakin 			if ((error = msleep(priv, &priv->ngd_mtx,
46547095f77SRoman Kurakin 			    PDROP | PCATCH | (PZERO + 1),
466547d3473SGleb Smirnoff 			    "ngdread", 0)) != 0)
467547d3473SGleb Smirnoff 				return (error);
468a8353960SJulian Elischer 		}
469547d3473SGleb Smirnoff 	} while (m == NULL);
470547d3473SGleb Smirnoff 
471547d3473SGleb Smirnoff 	while (m && uio->uio_resid > 0 && error == 0) {
472547d3473SGleb Smirnoff 		len = MIN(uio->uio_resid, m->m_len);
473547d3473SGleb Smirnoff 		if (len != 0)
474547d3473SGleb Smirnoff 			error = uiomove(mtod(m, void *), len, uio);
475547d3473SGleb Smirnoff 		m = m_free(m);
476a8353960SJulian Elischer 	}
477a8353960SJulian Elischer 
478547d3473SGleb Smirnoff 	if (m)
479547d3473SGleb Smirnoff 		m_freem(m);
480a8353960SJulian Elischer 
481547d3473SGleb Smirnoff 	return (error);
482a8353960SJulian Elischer }
483a8353960SJulian Elischer 
484a8353960SJulian Elischer /*
485a8353960SJulian Elischer  * This function is called when our device is written to.
486547d3473SGleb Smirnoff  * We read the data from userland into mbuf chain and pass it to the remote hook.
487a8353960SJulian Elischer  *
488a8353960SJulian Elischer  */
489a8353960SJulian Elischer static int
ngdwrite(struct cdev * dev,struct uio * uio,int flag)49089c9c53dSPoul-Henning Kamp ngdwrite(struct cdev *dev, struct uio *uio, int flag)
491a8353960SJulian Elischer {
492f71291a6SGleb Smirnoff 	struct epoch_tracker et;
493547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
494a8353960SJulian Elischer 	struct mbuf *m;
495547d3473SGleb Smirnoff 	int error = 0;
496a8353960SJulian Elischer 
497f2b9562cSGleb Smirnoff 	DBG;
498a8353960SJulian Elischer 
499547d3473SGleb Smirnoff 	if (uio->uio_resid == 0)
500a8353960SJulian Elischer 		return (0);
501a8353960SJulian Elischer 
502547d3473SGleb Smirnoff 	if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
503547d3473SGleb Smirnoff 		return (EIO);
504a8353960SJulian Elischer 
50544aae623SIan Lepore 	m = m_uiotombuf(uio, M_NOWAIT, 0, priv->ether_align, M_PKTHDR);
50644aae623SIan Lepore 	if (m == NULL)
507547d3473SGleb Smirnoff 		return (ENOBUFS);
508547d3473SGleb Smirnoff 
509f71291a6SGleb Smirnoff 	NET_EPOCH_ENTER(et);
510547d3473SGleb Smirnoff 	NG_SEND_DATA_ONLY(error, priv->hook, m);
511f71291a6SGleb Smirnoff 	NET_EPOCH_EXIT(et);
512547d3473SGleb Smirnoff 
513547d3473SGleb Smirnoff 	return (error);
514a8353960SJulian Elischer }
515a8353960SJulian Elischer 
516a8353960SJulian Elischer /*
517a8353960SJulian Elischer  * we are being polled/selected
518a8353960SJulian Elischer  * check if there is data available for read
519a8353960SJulian Elischer  */
520a8353960SJulian Elischer static int
ngdpoll(struct cdev * dev,int events,struct thread * td)52189c9c53dSPoul-Henning Kamp ngdpoll(struct cdev *dev, int events, struct thread *td)
522a8353960SJulian Elischer {
523547d3473SGleb Smirnoff 	priv_p	priv = (priv_p )dev->si_drv1;
524a8353960SJulian Elischer 	int revents = 0;
525a8353960SJulian Elischer 
526547d3473SGleb Smirnoff 	if (events & (POLLIN | POLLRDNORM) &&
527547d3473SGleb Smirnoff 	    !IFQ_IS_EMPTY(&priv->readq))
528a8353960SJulian Elischer 		revents |= events & (POLLIN | POLLRDNORM);
529a8353960SJulian Elischer 
530a8353960SJulian Elischer 	return (revents);
531a8353960SJulian Elischer }
532