ng_device.c revision 132448
198402Sjulian/*
298402Sjulian * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
398402Sjulian *
498402Sjulian * Redistribution and use in source and binary forms, with or without
598402Sjulian * modification, are permitted provided that the following conditions
698402Sjulian * are met:
798402Sjulian * 1. Redistributions of source code must retain the above copyright
898402Sjulian *    notice, this list of conditions and the following disclaimer.
998402Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1098402Sjulian *    notice, this list of conditions and the following disclaimer in the
1198402Sjulian *    documentation and/or other materials provided with the distribution.
1298402Sjulian *
1398402Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1498402Sjulian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1598402Sjulian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1698402Sjulian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1798402Sjulian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1898402Sjulian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1998402Sjulian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2098402Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2198402Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2298402Sjulian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2398402Sjulian *
2498402Sjulian * Netgraph "device" node
2598402Sjulian *
2698402Sjulian * This node presents a /dev/ngd%d device that interfaces to an other
2798402Sjulian * netgraph node.
2898402Sjulian *
2998402Sjulian * $FreeBSD: head/sys/netgraph/ng_device.c 132448 2004-07-20 13:16:17Z glebius $
3098402Sjulian *
3198402Sjulian */
3298402Sjulian
3398402Sjulian#include <sys/param.h>
34132446Sglebius#include <sys/conf.h>
35132446Sglebius#include <sys/ioccom.h>
3698402Sjulian#include <sys/kernel.h>
37132446Sglebius#include <sys/malloc.h>
3898402Sjulian#include <sys/mbuf.h>
39132446Sglebius#include <sys/poll.h>
40132446Sglebius#include <sys/queue.h>
41132446Sglebius#include <sys/systm.h>
4298402Sjulian#include <sys/uio.h>
4398402Sjulian
4498402Sjulian#include <netgraph/ng_message.h>
4598402Sjulian#include <netgraph/netgraph.h>
46132446Sglebius#include <netgraph/ng_device.h>
4798402Sjulian
4898402Sjulian/* turn this on for verbose messages */
4998402Sjulian#define NGD_DEBUG
5098402Sjulian
51132448Sglebius#define	ERROUT(x) do { error = (x); goto done; } while (0)
52132448Sglebius
5398402Sjulian/* Netgraph methods */
5498402Sjulianstatic ng_constructor_t	ng_device_cons;
5598402Sjulianstatic ng_rcvmsg_t	ng_device_rcvmsg;
5698402Sjulianstatic ng_newhook_t	ng_device_newhook;
5798402Sjulianstatic ng_connect_t 	ng_device_connect;
5898402Sjulianstatic ng_rcvdata_t	ng_device_rcvdata;
5998402Sjulianstatic ng_disconnect_t	ng_device_disconnect;
6098402Sjulianstatic int              ng_device_mod_event(module_t mod, int event, void *data);
6198402Sjulian
6298402Sjulianstatic int ng_device_init(void);
6398402Sjulianstatic int get_free_unit(void);
6498402Sjulian
6598402Sjulian/* Netgraph type */
6698402Sjulianstatic struct ng_type typestruct = {
67129823Sjulian	.version =	NG_ABI_VERSION,
68129823Sjulian	.name =		NG_DEVICE_NODE_TYPE,
69129823Sjulian	.mod_event =	ng_device_mod_event,
70129823Sjulian	.constructor =	ng_device_cons,
71129823Sjulian	.rcvmsg =	ng_device_rcvmsg,
72129823Sjulian	.newhook =	ng_device_newhook,
73129823Sjulian	.connect = 	ng_device_connect,
74129823Sjulian	.rcvdata =	ng_device_rcvdata,
75129823Sjulian	.disconnect =	ng_device_disconnect,
7698402Sjulian};
7798402SjulianNETGRAPH_INIT(device, &typestruct);
7898402Sjulian
7998402Sjulian/* per hook data */
8098402Sjulianstruct ngd_connection {
8198402Sjulian	SLIST_ENTRY(ngd_connection) links;
8298402Sjulian
83130585Sphk	struct cdev *ngddev;
8498402Sjulian	struct 	ng_hook *active_hook;
8598402Sjulian	char	*readq;
8698402Sjulian	int 	loc;
8798402Sjulian	int 	unit;
8898402Sjulian};
8998402Sjulian
9098402Sjulian/* global data */
9198402Sjulianstruct ngd_softc {
9298402Sjulian	SLIST_HEAD(, ngd_connection) head;
9398402Sjulian
9498402Sjulian	node_p node;
95125028Sharti	char nodename[NG_NODESIZ];
9698402Sjulian} ngd_softc;
9798402Sjulian
9898402Sjulian/* the per connection receiving queue maximum */
9998402Sjulian#define NGD_QUEUE_SIZE (1024*10)
10098402Sjulian
10198402Sjulian/* Maximum number of NGD devices */
10298402Sjulian#define MAX_NGD	25 		/* should be more than enough for now */
10398402Sjulian
10498402Sjulianstatic d_close_t ngdclose;
10598402Sjulianstatic d_open_t ngdopen;
10698402Sjulianstatic d_read_t ngdread;
10798402Sjulianstatic d_write_t ngdwrite;
10898402Sjulianstatic d_ioctl_t ngdioctl;
10998402Sjulianstatic d_poll_t ngdpoll;
11098402Sjulian
11198402Sjulianstatic struct cdevsw ngd_cdevsw = {
112126080Sphk	.d_version =	D_VERSION,
113126080Sphk	.d_flags =	D_NEEDGIANT,
114111815Sphk	.d_open =	ngdopen,
115111815Sphk	.d_close =	ngdclose,
116111815Sphk	.d_read =	ngdread,
117111815Sphk	.d_write =	ngdwrite,
118111815Sphk	.d_ioctl =	ngdioctl,
119111815Sphk	.d_poll =	ngdpoll,
120111815Sphk	.d_name =	"ngd",
12198402Sjulian};
12298402Sjulian
12398402Sjulian/*
12498402Sjulian * this holds all the stuff that should be done at load time
12598402Sjulian */
12698402Sjulianstatic int
12798402Sjulianng_device_mod_event(module_t mod, int event, void *data)
12898402Sjulian{
12998402Sjulian	int error = 0;
13098402Sjulian
13198402Sjulian#ifdef NGD_DEBUG
13298402Sjulian	printf("%s()\n",__func__);
13398402Sjulian#endif /* NGD_DEBUG */
13498402Sjulian
13598402Sjulian	switch (event) {
13698402Sjulian		case MOD_LOAD:
13798402Sjulian
13898402Sjulian			ng_device_init();
13998402Sjulian			break;
14098402Sjulian
14198402Sjulian		case MOD_UNLOAD:
14298402Sjulian			/* XXX do we need to do something specific ? */
14398402Sjulian			/* ng_device_breakdown */
14498402Sjulian			break;
14598402Sjulian
14698402Sjulian		default:
14798402Sjulian			error = EOPNOTSUPP;
14898402Sjulian			break;
14998402Sjulian	}
15098402Sjulian
15198402Sjulian	return(error);
15298402Sjulian}
15398402Sjulian
15498402Sjulian
15598402Sjulianstatic int
15698402Sjulianng_device_init()
15798402Sjulian{
15898402Sjulian        struct ngd_softc *sc = &ngd_softc;
15998402Sjulian
16098402Sjulian#ifdef NGD_DEBUG
16198402Sjulian	printf("%s()\n",__func__);
16298402Sjulian#endif /* NGD_DEBUG */
16398402Sjulian
16498402Sjulian	SLIST_INIT(&sc->head);
16598402Sjulian
16698402Sjulian        if (ng_make_node_common(&typestruct, &sc->node) != 0) {
16798402Sjulian                printf("%s(): ng_make_node_common failed\n",__func__);
16898402Sjulian                return(ENXIO);
16998402Sjulian        }
17098402Sjulian        sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE);
17198402Sjulian        if (ng_name_node(sc->node, sc->nodename)) {
17298402Sjulian                NG_NODE_UNREF(sc->node); /* make it go away again */
17398402Sjulian                printf("%s(): ng_name_node failed\n",__func__);
17498402Sjulian                return(ENXIO);
17598402Sjulian        }
17698402Sjulian        NG_NODE_SET_PRIVATE(sc->node, sc);
17798402Sjulian
17898402Sjulian	return(0);
17998402Sjulian}
18098402Sjulian
18198402Sjulian/*
18298402Sjulian * don't allow to be created, only the device can do that
18398402Sjulian */
18498402Sjulianstatic int
18598402Sjulianng_device_cons(node_p node)
18698402Sjulian{
18798402Sjulian
18898402Sjulian#ifdef NGD_DEBUG
18998402Sjulian	printf("%s()\n",__func__);
19098402Sjulian#endif /* NGD_DEBUG */
19198402Sjulian
19298402Sjulian	return(EINVAL);
19398402Sjulian}
19498402Sjulian
19598402Sjulian/*
19698402Sjulian * Receive control message. We just bounce it back as a reply.
19798402Sjulian */
19898402Sjulianstatic int
19998402Sjulianng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
20098402Sjulian{
20198402Sjulian        struct ngd_softc *sc = &ngd_softc;
20298402Sjulian	struct ng_mesg *msg;
20398402Sjulian	int error = 0;
20498402Sjulian	struct ngd_connection * connection = NULL;
20598402Sjulian	struct ngd_connection *tmp = NULL;
20698402Sjulian
20798402Sjulian#ifdef NGD_DEBUG
20898402Sjulian	printf("%s()\n",__func__);
20998402Sjulian#endif /* NGD_DEBUG */
21098402Sjulian
21198402Sjulian	NGI_GET_MSG(item, msg);
21298402Sjulian
21398402Sjulian	SLIST_FOREACH(tmp,&sc->head,links) {
21498402Sjulian		if(tmp->active_hook == lasthook) {
21598402Sjulian			connection = tmp;
21698402Sjulian		}
21798402Sjulian	}
21898402Sjulian	if(connection == NULL) {
21998402Sjulian		printf("%s(): connection is still NULL, no hook found\n",__func__);
22098402Sjulian		return(-1);
22198402Sjulian	}
22298402Sjulian
22398402Sjulian	return(error);
22498402Sjulian}
22598402Sjulian
22698402Sjulianstatic int
22798402Sjulianget_free_unit()
22898402Sjulian{
22998402Sjulian	struct ngd_connection *tmp = NULL;
23098402Sjulian	struct ngd_softc *sc = &ngd_softc;
23198402Sjulian	int n = 0;
23298402Sjulian	int unit = -1;
23398402Sjulian
23498402Sjulian#ifdef NGD_DEBUG
23598402Sjulian	printf("%s()\n",__func__);
23698402Sjulian#endif /* NGD_DEBUG */
23798402Sjulian
23898402Sjulian	/* When there is no list yet, the first device unit is always 0. */
23998402Sjulian	if SLIST_EMPTY(&sc->head) {
24098402Sjulian		unit = 0;
24198402Sjulian		return(unit);
24298402Sjulian	}
24398402Sjulian
24498402Sjulian	/* Just do a brute force loop to find the first free unit that is
24598402Sjulian	 * smaller than MAX_NGD.
24698402Sjulian	 * Set MAX_NGD to a large value, doesn't impact performance.
24798402Sjulian	 */
24898402Sjulian	for(n = 0;n<MAX_NGD && unit == -1;n++) {
24998402Sjulian		SLIST_FOREACH(tmp,&sc->head,links) {
25098402Sjulian
25198402Sjulian			if(tmp->unit == n) {
25298402Sjulian				unit = -1;
25398402Sjulian				break;
25498402Sjulian			}
25598402Sjulian			unit = n;
25698402Sjulian		}
25798402Sjulian	}
25898402Sjulian
25998402Sjulian	return(unit);
26098402Sjulian}
26198402Sjulian
26298402Sjulian/*
26398402Sjulian * incoming hook
26498402Sjulian */
26598402Sjulianstatic int
26698402Sjulianng_device_newhook(node_p node, hook_p hook, const char *name)
26798402Sjulian{
26898402Sjulian	struct ngd_softc *sc = &ngd_softc;
26998402Sjulian	struct ngd_connection * new_connection = NULL;
27098402Sjulian
27198402Sjulian#ifdef NGD_DEBUG
27298402Sjulian	printf("%s()\n",__func__);
273132448Sglebius#endif
27498402Sjulian
27598402Sjulian	new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT);
27698402Sjulian	if(new_connection == NULL) {
27798402Sjulian		printf("%s(): ERROR: new_connection == NULL\n",__func__);
278132448Sglebius		return(ENOMEM);
27998402Sjulian	}
28098402Sjulian
28198402Sjulian	new_connection->unit = get_free_unit();
28298402Sjulian	if(new_connection->unit<0) {
28398402Sjulian		printf("%s: No free unit found by get_free_unit(), "
284132448Sglebius				"increase MAX_NGD\n",__func__);
285132448Sglebius		free(new_connection, M_DEVBUF);
286132448Sglebius		return(EINVAL);
28798402Sjulian	}
28898402Sjulian	new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit);
28998402Sjulian	if(new_connection->ngddev == NULL) {
29098402Sjulian		printf("%s(): make_dev failed\n",__func__);
291132448Sglebius		free(new_connection, M_DEVBUF);
292132448Sglebius		return(EINVAL);
29398402Sjulian	}
29498402Sjulian
29598402Sjulian	new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
29698402Sjulian	if(new_connection->readq == NULL) {
29798402Sjulian		printf("%s(): readq malloc failed\n",__func__);
298132448Sglebius		free(new_connection, M_DEVBUF);
299132448Sglebius		return(ENOMEM);
30098402Sjulian	}
30198402Sjulian
30298402Sjulian	/* point to begin of buffer */
30398402Sjulian	new_connection->loc = 0;
30498402Sjulian	new_connection->active_hook = hook;
30598402Sjulian
30698402Sjulian	SLIST_INSERT_HEAD(&sc->head, new_connection, links);
30798402Sjulian
30898402Sjulian	return(0);
30998402Sjulian}
31098402Sjulian
31198402Sjulian/*
31298402Sjulian * we gave ok to a new hook
31398402Sjulian * now connect
31498402Sjulian */
31598402Sjulianstatic int
31698402Sjulianng_device_connect(hook_p hook)
31798402Sjulian{
31898402Sjulian
31998402Sjulian#ifdef NGD_DEBUG
32098402Sjulian	printf("%s()\n",__func__);
32198402Sjulian#endif /* NGD_DEBUG */
32298402Sjulian
32398402Sjulian	return(0);
32498402Sjulian}
32598402Sjulian
32698402Sjulian
32798402Sjulian/*
32898402Sjulian * Receive data from hook
32998402Sjulian */
33098402Sjulianstatic int
33198402Sjulianng_device_rcvdata(hook_p hook, item_p item)
33298402Sjulian{
33398402Sjulian	struct mbuf *m;
33498402Sjulian	struct ngd_softc *sc = &ngd_softc;
33598402Sjulian	struct ngd_connection * connection = NULL;
33698402Sjulian	struct ngd_connection * tmp;
33798402Sjulian	char *buffer;
338132448Sglebius	int error = 0;
33998402Sjulian
34098402Sjulian#ifdef NGD_DEBUG
34198402Sjulian	printf("%s()\n",__func__);
342132448Sglebius#endif
34398402Sjulian
344132448Sglebius	NGI_GET_M(item, m);
345132448Sglebius	NG_FREE_ITEM(item);
346132448Sglebius
347132448Sglebius	SLIST_FOREACH(tmp,&sc->head,links)
348132448Sglebius		if(tmp->active_hook == hook)
34998402Sjulian			connection = tmp;
350132448Sglebius
351132448Sglebius	if (connection == NULL) {
35298402Sjulian		printf("%s(): connection is still NULL, no hook found\n",__func__);
353132448Sglebius		ERROUT(ENOTCONN);
35498402Sjulian	}
35598402Sjulian
356132448Sglebius	if ((m = m_pullup(m,m->m_len)) == NULL) {
35798402Sjulian		printf("%s(): ERROR: m_pullup failed\n",__func__);
358132448Sglebius		ERROUT(ENOMEM);
35998402Sjulian	}
36098402Sjulian
36198402Sjulian	buffer = mtod(m,char *);
36298402Sjulian
363132448Sglebius	if ((connection->loc + m->m_len) < NGD_QUEUE_SIZE) {
364132448Sglebius	        memcpy(connection->readq + connection->loc, buffer, m->m_len);
36598402Sjulian		connection->loc += m->m_len;
366132448Sglebius	} else {
36798402Sjulian		printf("%s(): queue full, first read out a bit\n",__func__);
368132448Sglebius		ERROUT(ENOSPC);
369132448Sglebius	}
37098402Sjulian
371132448Sglebiusdone:
372132448Sglebius	NG_FREE_M(m);
373132448Sglebius	return(error);
37498402Sjulian}
37598402Sjulian
37698402Sjulian/*
37798402Sjulian * Removal of the last link destroys the node
37898402Sjulian */
37998402Sjulianstatic int
38098402Sjulianng_device_disconnect(hook_p hook)
38198402Sjulian{
38298402Sjulian	struct ngd_softc *sc = &ngd_softc;
38398402Sjulian	struct ngd_connection * connection = NULL;
38498402Sjulian	struct ngd_connection * tmp;
38598402Sjulian
38698402Sjulian#ifdef NGD_DEBUG
38798402Sjulian	printf("%s()\n",__func__);
388132448Sglebius#endif
38998402Sjulian
390132448Sglebius	SLIST_FOREACH(tmp,&sc->head,links)
391132448Sglebius		if(tmp->active_hook == hook)
39298402Sjulian			connection = tmp;
393132448Sglebius
39498402Sjulian	if(connection == NULL) {
39598402Sjulian		printf("%s(): connection is still NULL, no hook found\n",__func__);
396132448Sglebius		return(ENOTCONN);
39798402Sjulian	}
39898402Sjulian
399132448Sglebius        free(connection->readq, M_DEVBUF);
40098402Sjulian
40198402Sjulian	destroy_dev(connection->ngddev);
40298402Sjulian
40398402Sjulian	SLIST_REMOVE(&sc->head,connection,ngd_connection,links);
404132448Sglebius	free(connection, M_DEVBUF);
40598402Sjulian
40698402Sjulian	return(0);
40798402Sjulian}
40898402Sjulian/*
40998402Sjulian * the device is opened
41098402Sjulian */
41198402Sjulianstatic int
412130585Sphkngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
41398402Sjulian{
41498402Sjulian
41598402Sjulian#ifdef NGD_DEBUG
41698402Sjulian	printf("%s()\n",__func__);
41798402Sjulian#endif /* NGD_DEBUG */
41898402Sjulian
41998402Sjulian	return(0);
42098402Sjulian}
42198402Sjulian
42298402Sjulian/*
42398402Sjulian * the device is closed
42498402Sjulian */
42598402Sjulianstatic int
426130585Sphkngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
42798402Sjulian{
42898402Sjulian
42998402Sjulian#ifdef NGD_DEBUG
43098402Sjulian	printf("%s()\n",__func__);
43198402Sjulian#endif
43298402Sjulian
43398402Sjulian	return(0);
43498402Sjulian}
43598402Sjulian
43698402Sjulian
43798402Sjulian/*
43898402Sjulian * process ioctl
43998402Sjulian *
44098402Sjulian * they are translated into netgraph messages and passed on
44198402Sjulian *
44298402Sjulian */
44398402Sjulianstatic int
444130585Sphkngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
44598402Sjulian{
44698402Sjulian	struct ngd_softc *sc = &ngd_softc;
44798402Sjulian	struct ngd_connection * connection = NULL;
44898402Sjulian	struct ngd_connection * tmp;
44998402Sjulian	int error = 0;
45098402Sjulian	struct ng_mesg *msg;
45198402Sjulian        struct ngd_param_s * datap;
45298402Sjulian
45398402Sjulian#ifdef NGD_DEBUG
45498402Sjulian	printf("%s()\n",__func__);
45598402Sjulian#endif /* NGD_DEBUG */
45698402Sjulian
45798402Sjulian	SLIST_FOREACH(tmp,&sc->head,links) {
45898402Sjulian		if(tmp->ngddev == dev) {
45998402Sjulian			connection = tmp;
46098402Sjulian		}
46198402Sjulian	}
46298402Sjulian	if(connection == NULL) {
46398402Sjulian		printf("%s(): connection is still NULL, no dev found\n",__func__);
46498402Sjulian		return(-1);
46598402Sjulian	}
46698402Sjulian
46798402Sjulian	/* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */
46898402Sjulian	NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
46998402Sjulian			M_NOWAIT);
47098402Sjulian	if (msg == NULL) {
47198402Sjulian		printf("%s(): msg == NULL\n",__func__);
47298402Sjulian		goto nomsg;
47398402Sjulian	}
47498402Sjulian
47598402Sjulian	/* pass the ioctl data into the ->data area */
47698402Sjulian	datap = (struct ngd_param_s *)msg->data;
47798402Sjulian        datap->p = addr;
47898402Sjulian
479132446Sglebius	NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
48098402Sjulian	if(error)
48198402Sjulian		printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
48298402Sjulian
48398402Sjuliannomsg:
48498402Sjulian
48598402Sjulian	return(0);
48698402Sjulian}
48798402Sjulian
48898402Sjulian
48998402Sjulian/*
49098402Sjulian * This function is called when a read(2) is done to our device.
49198402Sjulian * We pass the data available in kernelspace on into userland using
49298402Sjulian * uiomove.
49398402Sjulian */
49498402Sjulianstatic int
495130585Sphkngdread(struct cdev *dev, struct uio *uio, int flag)
49698402Sjulian{
49798402Sjulian	int ret = 0, amnt;
49898402Sjulian	char buffer[uio->uio_resid+1];
49998402Sjulian	struct ngd_softc *sc = &ngd_softc;
50098402Sjulian	struct ngd_connection * connection = NULL;
50198402Sjulian	struct ngd_connection * tmp;
50298402Sjulian
50398402Sjulian#ifdef NGD_DEBUG
50498402Sjulian	printf("%s()\n",__func__);
50598402Sjulian#endif /* NGD_DEBUG */
50698402Sjulian
50798402Sjulian	SLIST_FOREACH(tmp,&sc->head,links) {
50898402Sjulian		if(tmp->ngddev == dev) {
50998402Sjulian			connection = tmp;
51098402Sjulian		}
51198402Sjulian	}
51298402Sjulian	if(connection == NULL) {
51398402Sjulian		printf("%s(): connection is still NULL, no dev found\n",__func__);
51498402Sjulian		return(-1);
51598402Sjulian	}
51698402Sjulian
51798402Sjulian	while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) {
51898402Sjulian		amnt = MIN(uio->uio_resid,connection->loc);
51998402Sjulian
52098402Sjulian		memcpy(buffer,connection->readq, amnt);
52198402Sjulian		memcpy(connection->readq, connection->readq+amnt,
52298402Sjulian				connection->loc-amnt);
52398402Sjulian		connection->loc -= amnt;
52498402Sjulian
52598402Sjulian		ret = uiomove((caddr_t)buffer, amnt, uio);
52698402Sjulian		if(ret != 0)
52798402Sjulian			goto error;
52898402Sjulian
52998402Sjulian	}
53098402Sjulian	return(0);
53198402Sjulian
53298402Sjulianerror:
53398402Sjulian	printf("%s(): uiomove returns error %d\n",__func__,ret);
53498402Sjulian	/* do error cleanup here */
53598402Sjulian	return(ret);
53698402Sjulian}
53798402Sjulian
53898402Sjulian
53998402Sjulian/*
54098402Sjulian * This function is called when our device is written to.
54198402Sjulian * We read the data from userland into our local buffer and pass it on
54298402Sjulian * into the remote hook.
54398402Sjulian *
54498402Sjulian */
54598402Sjulianstatic int
546130585Sphkngdwrite(struct cdev *dev, struct uio *uio, int flag)
54798402Sjulian{
54898402Sjulian	int ret;
54998402Sjulian	int error = 0;
55098402Sjulian	struct mbuf *m;
55198402Sjulian	char buffer[uio->uio_resid];
55298402Sjulian	int len = uio->uio_resid;
55398402Sjulian	struct ngd_softc *sc =& ngd_softc;
55498402Sjulian	struct ngd_connection * connection = NULL;
55598402Sjulian	struct ngd_connection * tmp;
55698402Sjulian
55798402Sjulian#ifdef NGD_DEBUG
55898402Sjulian	printf("%s()\n",__func__);
55998402Sjulian#endif /* NGD_DEBUG */
56098402Sjulian
56198402Sjulian	SLIST_FOREACH(tmp,&sc->head,links) {
56298402Sjulian		if(tmp->ngddev == dev) {
56398402Sjulian			connection = tmp;
56498402Sjulian		}
56598402Sjulian	}
56698402Sjulian
56798402Sjulian	if(connection == NULL) {
56898402Sjulian		printf("%s(): connection is still NULL, no dev found\n",__func__);
56998402Sjulian		return(-1);
57098402Sjulian	}
57198402Sjulian
57298402Sjulian	if (len > 0) {
57398402Sjulian		if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0)
57498402Sjulian			goto error;
57598402Sjulian	} else
57698402Sjulian		printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__);
57798402Sjulian
57898402Sjulian	m = m_devget(buffer,len,0,NULL,NULL);
57998402Sjulian
58098402Sjulian	NG_SEND_DATA_ONLY(error,connection->active_hook,m);
58198402Sjulian
58298402Sjulian	return(0);
58398402Sjulian
58498402Sjulianerror:
58598402Sjulian	/* do error cleanup here */
58698402Sjulian	printf("%s(): uiomove returned err: %d\n",__func__,ret);
58798402Sjulian
58898402Sjulian	return(ret);
58998402Sjulian}
59098402Sjulian
59198402Sjulian/*
59298402Sjulian * we are being polled/selected
59398402Sjulian * check if there is data available for read
59498402Sjulian */
59598402Sjulianstatic int
596130585Sphkngdpoll(struct cdev *dev, int events, struct thread *td)
59798402Sjulian{
59898402Sjulian	int revents = 0;
59998402Sjulian	struct ngd_softc *sc = &ngd_softc;
60098402Sjulian	struct ngd_connection * connection = NULL;
60198402Sjulian	struct ngd_connection * tmp;
60298402Sjulian
60398402Sjulian
60498402Sjulian	if (events & (POLLIN | POLLRDNORM)) {
60598402Sjulian		/* get the connection we have to know the loc from */
60698402Sjulian		SLIST_FOREACH(tmp,&sc->head,links) {
60798402Sjulian			if(tmp->ngddev == dev) {
60898402Sjulian				connection = tmp;
60998402Sjulian			}
61098402Sjulian		}
61198402Sjulian		if(connection == NULL) {
61298402Sjulian			printf("%s(): ERROR: connection is still NULL,"
61398402Sjulian				"no dev found\n",__func__);
61498402Sjulian			return(-1);
61598402Sjulian		}
61698402Sjulian
61798402Sjulian		if (connection->loc > 0)
61898402Sjulian			revents |= events & (POLLIN | POLLRDNORM);
61998402Sjulian	}
62098402Sjulian
62198402Sjulian	return(revents);
62298402Sjulian}
623