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