ng_device.c revision 141341
1139823Simp/*-
298402Sjulian * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
3137525Sglebius * Copyright (c) 2004 Gleb Smirnoff <glebius@FreeBSD.org>
498402Sjulian *
598402Sjulian * Redistribution and use in source and binary forms, with or without
698402Sjulian * modification, are permitted provided that the following conditions
798402Sjulian * are met:
898402Sjulian * 1. Redistributions of source code must retain the above copyright
998402Sjulian *    notice, this list of conditions and the following disclaimer.
1098402Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1198402Sjulian *    notice, this list of conditions and the following disclaimer in the
1298402Sjulian *    documentation and/or other materials provided with the distribution.
1398402Sjulian *
1498402Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1598402Sjulian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1698402Sjulian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1798402Sjulian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1898402Sjulian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1998402Sjulian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2098402Sjulian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2198402Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2298402Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2398402Sjulian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2498402Sjulian *
2598402Sjulian * Netgraph "device" node
2698402Sjulian *
27136673Sglebius * This node presents a /dev/ngd%d device that interfaces to an other
2898402Sjulian * netgraph node.
2998402Sjulian *
3098402Sjulian * $FreeBSD: head/sys/netgraph/ng_device.c 141341 2005-02-05 08:28:36Z ru $
3198402Sjulian *
3298402Sjulian */
3398402Sjulian
34136673Sglebius#if 0
35137100Sglebius#define	DBG do { printf("ng_device: %s\n", __func__ ); } while (0)
36136673Sglebius#else
37137100Sglebius#define	DBG do {} while (0)
38136673Sglebius#endif
39136673Sglebius
4098402Sjulian#include <sys/param.h>
41132446Sglebius#include <sys/conf.h>
42132446Sglebius#include <sys/ioccom.h>
4398402Sjulian#include <sys/kernel.h>
44132446Sglebius#include <sys/malloc.h>
4598402Sjulian#include <sys/mbuf.h>
46132446Sglebius#include <sys/poll.h>
47132446Sglebius#include <sys/queue.h>
48136673Sglebius#include <sys/socket.h>
49132446Sglebius#include <sys/systm.h>
5098402Sjulian#include <sys/uio.h>
51136673Sglebius#include <sys/vnode.h>
5298402Sjulian
53136673Sglebius#include <net/if.h>
54136673Sglebius#include <net/if_var.h>
55136673Sglebius#include <netinet/in.h>
56136673Sglebius#include <netinet/in_systm.h>
57136673Sglebius#include <netinet/ip.h>
58136673Sglebius
5998402Sjulian#include <netgraph/ng_message.h>
6098402Sjulian#include <netgraph/netgraph.h>
61132446Sglebius#include <netgraph/ng_device.h>
6298402Sjulian
63132448Sglebius#define	ERROUT(x) do { error = (x); goto done; } while (0)
64132448Sglebius
6598402Sjulian/* Netgraph methods */
66141341Srustatic int		ng_device_mod_event(module_t, int, void *);
67136673Sglebiusstatic ng_constructor_t	ng_device_constructor;
6898402Sjulianstatic ng_rcvmsg_t	ng_device_rcvmsg;
69136673Sglebiusstatic ng_shutdown_t	ng_device_shutdown;
7098402Sjulianstatic ng_newhook_t	ng_device_newhook;
7198402Sjulianstatic ng_rcvdata_t	ng_device_rcvdata;
7298402Sjulianstatic ng_disconnect_t	ng_device_disconnect;
7398402Sjulian
7498402Sjulian/* Netgraph type */
75136673Sglebiusstatic struct ng_type ngd_typestruct = {
76129823Sjulian	.version =	NG_ABI_VERSION,
77129823Sjulian	.name =		NG_DEVICE_NODE_TYPE,
78141341Sru	.mod_event =	ng_device_mod_event,
79136673Sglebius	.constructor =	ng_device_constructor,
80136673Sglebius	.rcvmsg	=	ng_device_rcvmsg,
81136673Sglebius	.shutdown = 	ng_device_shutdown,
82129823Sjulian	.newhook =	ng_device_newhook,
83129823Sjulian	.rcvdata =	ng_device_rcvdata,
84129823Sjulian	.disconnect =	ng_device_disconnect,
8598402Sjulian};
86136673SglebiusNETGRAPH_INIT(device, &ngd_typestruct);
8798402Sjulian
88136673Sglebius/* per node data */
89136673Sglebiusstruct ngd_private {
90136673Sglebius	struct	ifqueue	readq;
91136673Sglebius	SLIST_ENTRY(ngd_private) links;
92136673Sglebius	struct	ng_node	*node;
93136673Sglebius	struct	ng_hook	*hook;
94136673Sglebius	struct	cdev	*ngddev;
95136673Sglebius	struct	mtx	ngd_mtx;
96136673Sglebius	int 		unit;
97136673Sglebius	uint16_t	flags;
98136673Sglebius#define	NGDF_OPEN	0x0001
99136673Sglebius#define	NGDF_RWAIT	0x0002
10098402Sjulian};
101136673Sglebiustypedef struct ngd_private *priv_p;
10298402Sjulian
103136673Sglebius/* List of all active nodes and mutex to protect it */
104136673Sglebiusstatic SLIST_HEAD(, ngd_private) ngd_nodes = SLIST_HEAD_INITIALIZER(ngd_nodes);
105136673Sglebiusstatic struct mtx	ng_device_mtx;
10698402Sjulian
10798402Sjulian/* Maximum number of NGD devices */
108136673Sglebius#define MAX_NGD	25	/* should be more than enough for now */
10998402Sjulian
11098402Sjulianstatic d_close_t ngdclose;
11198402Sjulianstatic d_open_t ngdopen;
11298402Sjulianstatic d_read_t ngdread;
11398402Sjulianstatic d_write_t ngdwrite;
114136673Sglebius#if 0
11598402Sjulianstatic d_ioctl_t ngdioctl;
116136673Sglebius#endif
11798402Sjulianstatic d_poll_t ngdpoll;
11898402Sjulian
11998402Sjulianstatic struct cdevsw ngd_cdevsw = {
120126080Sphk	.d_version =	D_VERSION,
121111815Sphk	.d_open =	ngdopen,
122111815Sphk	.d_close =	ngdclose,
123111815Sphk	.d_read =	ngdread,
124111815Sphk	.d_write =	ngdwrite,
125136673Sglebius#if 0
126111815Sphk	.d_ioctl =	ngdioctl,
127136673Sglebius#endif
128111815Sphk	.d_poll =	ngdpoll,
129136673Sglebius	.d_name =	NG_DEVICE_DEVNAME,
13098402Sjulian};
13198402Sjulian
132136673Sglebius/* Helper functions */
133136673Sglebiusstatic int get_free_unit(void);
134136673Sglebius
135136673Sglebius/******************************************************************************
136136673Sglebius *  Netgraph methods
137136673Sglebius ******************************************************************************/
138136673Sglebius
139136673Sglebius/*
140136673Sglebius * create new node
14198402Sjulian */
14298402Sjulianstatic int
143136673Sglebiusng_device_constructor(node_p node)
14498402Sjulian{
145136673Sglebius	priv_p	priv;
14698402Sjulian
147137022Sglebius	DBG;
14898402Sjulian
149136673Sglebius	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
150136673Sglebius	if (priv == NULL)
151136673Sglebius		return (ENOMEM);
15298402Sjulian
153136673Sglebius	mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
154136673Sglebius	mtx_lock(&priv->ngd_mtx);
15598402Sjulian
156136673Sglebius	mtx_lock(&ng_device_mtx);
157136673Sglebius
158136673Sglebius	priv->unit = get_free_unit();
159136673Sglebius	if(priv->unit < 0) {
160136673Sglebius		printf("%s: No free unit found by get_free_unit(), "
161136673Sglebius				"increase MAX_NGD\n",__func__);
162136673Sglebius		mtx_unlock(&ng_device_mtx);
163136673Sglebius		mtx_destroy(&priv->ngd_mtx);
164136673Sglebius		FREE(priv, M_NETGRAPH);
165136673Sglebius		return(EINVAL);
16698402Sjulian	}
16798402Sjulian
168136673Sglebius	priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT,
169136673Sglebius	    GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
170136673Sglebius	if(priv->ngddev == NULL) {
171136673Sglebius		printf("%s(): make_dev() failed\n",__func__);
172136673Sglebius		mtx_unlock(&ng_device_mtx);
173136673Sglebius		mtx_destroy(&priv->ngd_mtx);
174136673Sglebius		FREE(priv, M_NETGRAPH);
175136673Sglebius		return(EINVAL);
176136673Sglebius	}
17798402Sjulian
178136673Sglebius	SLIST_INSERT_HEAD(&ngd_nodes, priv, links);
17998402Sjulian
180136673Sglebius	mtx_unlock(&ng_device_mtx);
18198402Sjulian
182136673Sglebius	mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
183136673Sglebius	IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
18498402Sjulian
185136673Sglebius	/* Link everything together */
186136673Sglebius	NG_NODE_SET_PRIVATE(node, priv);
187136673Sglebius	priv->node = node;
188136673Sglebius	priv->ngddev->si_drv1 = priv;
189136673Sglebius
190136673Sglebius	mtx_unlock(&priv->ngd_mtx);
19198402Sjulian
19298402Sjulian	return(0);
19398402Sjulian}
19498402Sjulian
195136673Sglebius/*
196136673Sglebius * Process control message.
19798402Sjulian */
19898402Sjulian
19998402Sjulianstatic int
20098402Sjulianng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
20198402Sjulian{
202136673Sglebius	const priv_p priv = NG_NODE_PRIVATE(node);
20398402Sjulian	struct ng_mesg *msg;
204136673Sglebius	struct ng_mesg *resp = NULL;
20598402Sjulian	int error = 0;
20698402Sjulian
207136673Sglebius	NGI_GET_MSG(item, msg);
20898402Sjulian
209136673Sglebius	if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
210136673Sglebius		switch (msg->header.cmd) {
211136673Sglebius		case NGM_DEVICE_GET_DEVNAME:
212136673Sglebius			/* XXX: Fix when NGD_MAX us bigger */
213136673Sglebius			NG_MKRESPONSE(resp, msg,
214136673Sglebius			    strlen(NG_DEVICE_DEVNAME) + 3, M_NOWAIT);
21598402Sjulian
216136673Sglebius			if (resp == NULL)
217136673Sglebius				ERROUT(ENOMEM);
21898402Sjulian
219136673Sglebius			strlcpy((char *)resp->data, priv->ngddev->si_name,
220136673Sglebius			    strlen(priv->ngddev->si_name) + 1);
221136673Sglebius			break;
22298402Sjulian
223136673Sglebius		default:
224136673Sglebius			error = EINVAL;
225136673Sglebius			break;
22698402Sjulian		}
227136673Sglebius	} else
228136673Sglebius		error = EINVAL;
22998402Sjulian
230136673Sglebiusdone:
231136673Sglebius	NG_RESPOND_MSG(error, node, item, resp);
232136673Sglebius	NG_FREE_MSG(msg);
233136673Sglebius	return (error);
23498402Sjulian}
23598402Sjulian
23698402Sjulian/*
237136673Sglebius * Accept incoming hook. We support only one hook per node.
23898402Sjulian */
23998402Sjulianstatic int
24098402Sjulianng_device_newhook(node_p node, hook_p hook, const char *name)
24198402Sjulian{
242136673Sglebius	priv_p priv = NG_NODE_PRIVATE(node);
24398402Sjulian
244137022Sglebius	DBG;
24598402Sjulian
246136673Sglebius	/* We have only one hook per node */
247136673Sglebius	if (priv->hook != NULL)
248136673Sglebius		return (EISCONN);
24998402Sjulian
250136673Sglebius	priv->hook = hook;
25198402Sjulian
25298402Sjulian	return(0);
25398402Sjulian}
25498402Sjulian
25598402Sjulian/*
256136673Sglebius * Receive data from hook, write it to device.
25798402Sjulian */
25898402Sjulianstatic int
25998402Sjulianng_device_rcvdata(hook_p hook, item_p item)
26098402Sjulian{
261136673Sglebius	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
26298402Sjulian	struct mbuf *m;
26398402Sjulian
264137022Sglebius	DBG;
26598402Sjulian
266132448Sglebius	NGI_GET_M(item, m);
267132448Sglebius	NG_FREE_ITEM(item);
268132448Sglebius
269136673Sglebius	IF_LOCK(&priv->readq);
270136673Sglebius	if (_IF_QFULL(&priv->readq)) {
271136673Sglebius		_IF_DROP(&priv->readq);
272136673Sglebius		IF_UNLOCK(&priv->readq);
273136673Sglebius		NG_FREE_M(m);
274136673Sglebius		return (ENOBUFS);
27598402Sjulian	}
27698402Sjulian
277136673Sglebius	_IF_ENQUEUE(&priv->readq, m);
278136673Sglebius	IF_UNLOCK(&priv->readq);
279136673Sglebius	mtx_lock(&priv->ngd_mtx);
280136673Sglebius	if (priv->flags & NGDF_RWAIT) {
281136673Sglebius		priv->flags &= ~NGDF_RWAIT;
282136673Sglebius		wakeup(priv);
28398402Sjulian	}
284136673Sglebius	mtx_unlock(&priv->ngd_mtx);
28598402Sjulian
286136673Sglebius	return(0);
28798402Sjulian}
28898402Sjulian
28998402Sjulian/*
290136673Sglebius * Removal of the hook destroys the node.
29198402Sjulian */
29298402Sjulianstatic int
29398402Sjulianng_device_disconnect(hook_p hook)
29498402Sjulian{
295136673Sglebius	priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
29698402Sjulian
297137022Sglebius	DBG;
29898402Sjulian
299136673Sglebius	destroy_dev(priv->ngddev);
300136673Sglebius	mtx_destroy(&priv->ngd_mtx);
301132448Sglebius
302136673Sglebius	mtx_lock(&ng_device_mtx);
303136673Sglebius	SLIST_REMOVE(&ngd_nodes, priv, ngd_private, links);
304136673Sglebius	mtx_unlock(&ng_device_mtx);
30598402Sjulian
306136673Sglebius	IF_DRAIN(&priv->readq);
307136673Sglebius	mtx_destroy(&(priv)->readq.ifq_mtx);
30898402Sjulian
309136673Sglebius	FREE(priv, M_NETGRAPH);
31098402Sjulian
311136673Sglebius	ng_rmnode_self(NG_HOOK_NODE(hook));
31298402Sjulian
31398402Sjulian	return(0);
31498402Sjulian}
315136673Sglebius
31698402Sjulian/*
317136673Sglebius * Node shutdown. Everything is already done in disconnect method.
31898402Sjulian */
31998402Sjulianstatic int
320136673Sglebiusng_device_shutdown(node_p node)
321136673Sglebius{
322136673Sglebius	NG_NODE_UNREF(node);
323136673Sglebius	return (0);
324136673Sglebius}
325136673Sglebius
326136673Sglebius/******************************************************************************
327136673Sglebius *  Device methods
328136673Sglebius ******************************************************************************/
329136673Sglebius
330136673Sglebius/*
331136673Sglebius * the device is opened
332136673Sglebius */
333136673Sglebiusstatic int
334130585Sphkngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
33598402Sjulian{
336136673Sglebius	priv_p	priv = (priv_p )dev->si_drv1;
33798402Sjulian
338137022Sglebius	DBG;
339137022Sglebius
340136673Sglebius	mtx_lock(&priv->ngd_mtx);
341136673Sglebius	priv->flags |= NGDF_OPEN;
342136673Sglebius	mtx_unlock(&priv->ngd_mtx);
34398402Sjulian
34498402Sjulian	return(0);
34598402Sjulian}
34698402Sjulian
34798402Sjulian/*
348136673Sglebius * the device is closed
34998402Sjulian */
35098402Sjulianstatic int
351130585Sphkngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
35298402Sjulian{
353136673Sglebius	priv_p	priv = (priv_p )dev->si_drv1;
35498402Sjulian
355137022Sglebius	DBG;
356136673Sglebius	mtx_lock(&priv->ngd_mtx);
357136673Sglebius	priv->flags &= ~NGDF_OPEN;
358136673Sglebius	mtx_unlock(&priv->ngd_mtx);
35998402Sjulian
36098402Sjulian	return(0);
36198402Sjulian}
36298402Sjulian
363136673Sglebius#if 0	/*
364136673Sglebius	 * The ioctl is transformed into netgraph control message.
365136673Sglebius	 * We do not process them, yet.
366136673Sglebius	 */
36798402Sjulian/*
36898402Sjulian * process ioctl
36998402Sjulian *
37098402Sjulian * they are translated into netgraph messages and passed on
371136673Sglebius *
37298402Sjulian */
37398402Sjulianstatic int
374130585Sphkngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
37598402Sjulian{
37698402Sjulian	struct ngd_softc *sc = &ngd_softc;
37798402Sjulian	struct ngd_connection * connection = NULL;
37898402Sjulian	struct ngd_connection * tmp;
37998402Sjulian	int error = 0;
38098402Sjulian	struct ng_mesg *msg;
381136673Sglebius	struct ngd_param_s * datap;
38298402Sjulian
383137022Sglebius	DBG;
38498402Sjulian
38598402Sjulian	SLIST_FOREACH(tmp,&sc->head,links) {
38698402Sjulian		if(tmp->ngddev == dev) {
38798402Sjulian			connection = tmp;
38898402Sjulian		}
38998402Sjulian	}
39098402Sjulian	if(connection == NULL) {
39198402Sjulian		printf("%s(): connection is still NULL, no dev found\n",__func__);
39298402Sjulian		return(-1);
39398402Sjulian	}
39498402Sjulian
395136673Sglebius	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
39698402Sjulian			M_NOWAIT);
39798402Sjulian	if (msg == NULL) {
39898402Sjulian		printf("%s(): msg == NULL\n",__func__);
39998402Sjulian		goto nomsg;
40098402Sjulian	}
40198402Sjulian
40298402Sjulian	/* pass the ioctl data into the ->data area */
40398402Sjulian	datap = (struct ngd_param_s *)msg->data;
404136673Sglebius	datap->p = addr;
40598402Sjulian
406132446Sglebius	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
40798402Sjulian	if(error)
40898402Sjulian		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
40998402Sjulian
41098402Sjuliannomsg:
41198402Sjulian
41298402Sjulian	return(0);
41398402Sjulian}
414136673Sglebius#endif /* if 0 */
41598402Sjulian
41698402Sjulian/*
41798402Sjulian * This function is called when a read(2) is done to our device.
418136673Sglebius * We process one mbuf from queue.
41998402Sjulian */
42098402Sjulianstatic int
421130585Sphkngdread(struct cdev *dev, struct uio *uio, int flag)
42298402Sjulian{
423136673Sglebius	priv_p	priv = (priv_p )dev->si_drv1;
424136673Sglebius	struct mbuf *m;
425136673Sglebius	int len, error = 0;
42698402Sjulian
427137022Sglebius	DBG;
42898402Sjulian
429136673Sglebius	/* get an mbuf */
430136673Sglebius	do {
431136673Sglebius		IF_DEQUEUE(&priv->readq, m);
432136673Sglebius		if (m == NULL) {
433136673Sglebius			if (flag & IO_NDELAY)
434136673Sglebius				return (EWOULDBLOCK);
435136673Sglebius			mtx_lock(&priv->ngd_mtx);
436136673Sglebius			priv->flags |= NGDF_RWAIT;
437139331Srik			if ((error = msleep(priv, &priv->ngd_mtx,
438139331Srik			    PDROP | PCATCH | (PZERO + 1),
439136673Sglebius			    "ngdread", 0)) != 0)
440136673Sglebius				return (error);
44198402Sjulian		}
442136673Sglebius	} while (m == NULL);
443136673Sglebius
444136673Sglebius	while (m && uio->uio_resid > 0 && error == 0) {
445136673Sglebius		len = MIN(uio->uio_resid, m->m_len);
446136673Sglebius		if (len != 0)
447136673Sglebius			error = uiomove(mtod(m, void *), len, uio);
448136673Sglebius		m = m_free(m);
44998402Sjulian	}
45098402Sjulian
451136673Sglebius	if (m)
452136673Sglebius		m_freem(m);
45398402Sjulian
454136673Sglebius	return (error);
45598402Sjulian}
45698402Sjulian
45798402Sjulian
458136673Sglebius/*
45998402Sjulian * This function is called when our device is written to.
460136673Sglebius * We read the data from userland into mbuf chain and pass it to the remote hook.
46198402Sjulian *
46298402Sjulian */
46398402Sjulianstatic int
464130585Sphkngdwrite(struct cdev *dev, struct uio *uio, int flag)
46598402Sjulian{
466136673Sglebius	priv_p	priv = (priv_p )dev->si_drv1;
467136673Sglebius	struct mbuf *m;
46898402Sjulian	int error = 0;
46998402Sjulian
470137022Sglebius	DBG;
47198402Sjulian
472136673Sglebius	if (uio->uio_resid == 0)
473136673Sglebius		return (0);
47498402Sjulian
475136673Sglebius	if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
476136673Sglebius		return (EIO);
47798402Sjulian
478136673Sglebius	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL)
479136673Sglebius		return (ENOBUFS);
48098402Sjulian
481136673Sglebius	NG_SEND_DATA_ONLY(error, priv->hook, m);
48298402Sjulian
483136673Sglebius	return (error);
48498402Sjulian}
48598402Sjulian
48698402Sjulian/*
48798402Sjulian * we are being polled/selected
48898402Sjulian * check if there is data available for read
48998402Sjulian */
49098402Sjulianstatic int
491130585Sphkngdpoll(struct cdev *dev, int events, struct thread *td)
49298402Sjulian{
493136673Sglebius	priv_p	priv = (priv_p )dev->si_drv1;
49498402Sjulian	int revents = 0;
49598402Sjulian
496136673Sglebius	if (events & (POLLIN | POLLRDNORM) &&
497136673Sglebius	    !IFQ_IS_EMPTY(&priv->readq))
498136673Sglebius		revents |= events & (POLLIN | POLLRDNORM);
49998402Sjulian
500136673Sglebius	return (revents);
501136673Sglebius}
502136673Sglebius
503136673Sglebius/******************************************************************************
504136673Sglebius *  Helper subroutines
505136673Sglebius ******************************************************************************/
506136673Sglebius
507136673Sglebiusstatic int
508136673Sglebiusget_free_unit()
509136673Sglebius{
510136673Sglebius	struct ngd_private *priv = NULL;
511136673Sglebius	int n = 0;
512136673Sglebius	int unit = -1;
513136673Sglebius
514137022Sglebius	DBG;
515136673Sglebius
516136673Sglebius	mtx_assert(&ng_device_mtx, MA_OWNED);
517136673Sglebius
518136673Sglebius	/* When there is no list yet, the first device unit is always 0. */
519136673Sglebius	if SLIST_EMPTY(&ngd_nodes)
520136673Sglebius		return(0);
521136673Sglebius
522136673Sglebius	/* Just do a brute force loop to find the first free unit that is
523136673Sglebius	 * smaller than MAX_NGD.
524136673Sglebius	 * Set MAX_NGD to a large value, doesn't impact performance.
525136673Sglebius	 */
526136673Sglebius	for(n = 0; n<MAX_NGD && unit == -1; n++) {
527136673Sglebius		SLIST_FOREACH(priv, &ngd_nodes, links) {
528136673Sglebius
529136673Sglebius			if(priv->unit == n) {
530136673Sglebius				unit = -1;
531136673Sglebius				break;
53298402Sjulian			}
533136673Sglebius			unit = n;
53498402Sjulian		}
53598402Sjulian	}
53698402Sjulian
537136673Sglebius	return (unit);
53898402Sjulian}
539141341Sru
540141341Sru/*
541141341Sru * Handle loading and unloading for this node type.
542141341Sru */
543141341Srustatic int
544141341Srung_device_mod_event(module_t mod, int event, void *data)
545141341Sru{
546141341Sru	int error = 0;
547141341Sru
548141341Sru	switch (event) {
549141341Sru	case MOD_LOAD:
550141341Sru		mtx_init(&ng_device_mtx, "ng_device", NULL, MTX_DEF);
551141341Sru		break;
552141341Sru	case MOD_UNLOAD:
553141341Sru		mtx_destroy(&ng_device_mtx);
554141341Sru		break;
555141341Sru	default:
556141341Sru		error = EOPNOTSUPP;
557141341Sru		break;
558141341Sru	}
559141341Sru	return (error);
560141341Sru}
561