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