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