1a8353960SJulian Elischer /* 2a8353960SJulian Elischer * Copyright (c) 2002 Mark Santcroos <marks@ripe.net> 3a8353960SJulian Elischer * 4a8353960SJulian Elischer * Redistribution and use in source and binary forms, with or without 5a8353960SJulian Elischer * modification, are permitted provided that the following conditions 6a8353960SJulian Elischer * are met: 7a8353960SJulian Elischer * 1. Redistributions of source code must retain the above copyright 8a8353960SJulian Elischer * notice, this list of conditions and the following disclaimer. 9a8353960SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 10a8353960SJulian Elischer * notice, this list of conditions and the following disclaimer in the 11a8353960SJulian Elischer * documentation and/or other materials provided with the distribution. 12a8353960SJulian Elischer * 3. The name of the author may not be used to endorse or promote products 13a8353960SJulian Elischer * derived from this software without specific prior written permission. 14a8353960SJulian Elischer * 15a8353960SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16a8353960SJulian Elischer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17a8353960SJulian Elischer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18a8353960SJulian Elischer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19a8353960SJulian Elischer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20a8353960SJulian Elischer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21a8353960SJulian Elischer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22a8353960SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23a8353960SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24a8353960SJulian Elischer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25a8353960SJulian Elischer * 26a8353960SJulian Elischer * Netgraph "device" node 27a8353960SJulian Elischer * 28a8353960SJulian Elischer * This node presents a /dev/ngd%d device that interfaces to an other 29a8353960SJulian Elischer * netgraph node. 30a8353960SJulian Elischer * 31a8353960SJulian Elischer * $FreeBSD$ 32a8353960SJulian Elischer * 33a8353960SJulian Elischer */ 34a8353960SJulian Elischer 35a8353960SJulian Elischer #include <sys/param.h> 36a8353960SJulian Elischer #include <sys/systm.h> 37a8353960SJulian Elischer #include <sys/kernel.h> 38a8353960SJulian Elischer #include <sys/mbuf.h> 39a8353960SJulian Elischer #include <sys/uio.h> 40a8353960SJulian Elischer #include <sys/queue.h> 41a8353960SJulian Elischer #include <sys/malloc.h> 42a8353960SJulian Elischer #include <sys/conf.h> 43a8353960SJulian Elischer #include <sys/poll.h> 44a8353960SJulian Elischer #include <sys/ioccom.h> 45a8353960SJulian Elischer 46a8353960SJulian Elischer #include <netgraph/ng_message.h> 47a8353960SJulian Elischer #include <netgraph/netgraph.h> 48a8353960SJulian Elischer 49a8353960SJulian Elischer #include "ng_device.h" 50a8353960SJulian Elischer 51a8353960SJulian Elischer /* turn this on for verbose messages */ 52a8353960SJulian Elischer #define NGD_DEBUG 53a8353960SJulian Elischer 54a8353960SJulian Elischer /* Netgraph methods */ 55a8353960SJulian Elischer static ng_constructor_t ng_device_cons; 56a8353960SJulian Elischer static ng_rcvmsg_t ng_device_rcvmsg; 57a8353960SJulian Elischer static ng_newhook_t ng_device_newhook; 58a8353960SJulian Elischer static ng_connect_t ng_device_connect; 59a8353960SJulian Elischer static ng_rcvdata_t ng_device_rcvdata; 60a8353960SJulian Elischer static ng_disconnect_t ng_device_disconnect; 61a8353960SJulian Elischer static int ng_device_mod_event(module_t mod, int event, void *data); 62a8353960SJulian Elischer 63a8353960SJulian Elischer static int ng_device_init(void); 64a8353960SJulian Elischer static int get_free_unit(void); 65a8353960SJulian Elischer 66a8353960SJulian Elischer /* Netgraph type */ 67a8353960SJulian Elischer static struct ng_type typestruct = { 68a8353960SJulian Elischer NG_ABI_VERSION, /* version */ 69a8353960SJulian Elischer NG_DEVICE_NODE_TYPE, /* name */ 70a8353960SJulian Elischer ng_device_mod_event, /* modevent */ 71a8353960SJulian Elischer ng_device_cons, /* constructor */ 72a8353960SJulian Elischer ng_device_rcvmsg, /* receive msg */ 73a8353960SJulian Elischer NULL, /* shutdown */ 74a8353960SJulian Elischer ng_device_newhook, /* newhook */ 75a8353960SJulian Elischer NULL, /* findhook */ 76a8353960SJulian Elischer ng_device_connect, /* connect */ 77a8353960SJulian Elischer ng_device_rcvdata, /* receive data */ 78a8353960SJulian Elischer ng_device_disconnect, /* disconnect */ 79a8353960SJulian Elischer NULL 80a8353960SJulian Elischer }; 81a8353960SJulian Elischer NETGRAPH_INIT(device, &typestruct); 82a8353960SJulian Elischer 83a8353960SJulian Elischer /* per hook data */ 84a8353960SJulian Elischer struct ngd_connection { 85a8353960SJulian Elischer SLIST_ENTRY(ngd_connection) links; 86a8353960SJulian Elischer 87a8353960SJulian Elischer dev_t ngddev; 88a8353960SJulian Elischer struct ng_hook *active_hook; 89a8353960SJulian Elischer char *readq; 90a8353960SJulian Elischer int loc; 91a8353960SJulian Elischer int unit; 92a8353960SJulian Elischer }; 93a8353960SJulian Elischer 94a8353960SJulian Elischer /* global data */ 95a8353960SJulian Elischer struct ngd_softc { 96a8353960SJulian Elischer SLIST_HEAD(, ngd_connection) head; 97a8353960SJulian Elischer 98a8353960SJulian Elischer node_p node; 9987e2c66aSHartmut Brandt char nodename[NG_NODESIZ]; 100a8353960SJulian Elischer } ngd_softc; 101a8353960SJulian Elischer 102a8353960SJulian Elischer /* the per connection receiving queue maximum */ 103a8353960SJulian Elischer #define NGD_QUEUE_SIZE (1024*10) 104a8353960SJulian Elischer 105a8353960SJulian Elischer /* Maximum number of NGD devices */ 106a8353960SJulian Elischer #define MAX_NGD 25 /* should be more than enough for now */ 107a8353960SJulian Elischer 108a8353960SJulian Elischer static d_close_t ngdclose; 109a8353960SJulian Elischer static d_open_t ngdopen; 110a8353960SJulian Elischer static d_read_t ngdread; 111a8353960SJulian Elischer static d_write_t ngdwrite; 112a8353960SJulian Elischer static d_ioctl_t ngdioctl; 113a8353960SJulian Elischer static d_poll_t ngdpoll; 114a8353960SJulian Elischer 115a8353960SJulian Elischer static struct cdevsw ngd_cdevsw = { 116dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 117dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1187ac40f5fSPoul-Henning Kamp .d_open = ngdopen, 1197ac40f5fSPoul-Henning Kamp .d_close = ngdclose, 1207ac40f5fSPoul-Henning Kamp .d_read = ngdread, 1217ac40f5fSPoul-Henning Kamp .d_write = ngdwrite, 1227ac40f5fSPoul-Henning Kamp .d_ioctl = ngdioctl, 1237ac40f5fSPoul-Henning Kamp .d_poll = ngdpoll, 1247ac40f5fSPoul-Henning Kamp .d_name = "ngd", 125a8353960SJulian Elischer }; 126a8353960SJulian Elischer 127a8353960SJulian Elischer /* 128a8353960SJulian Elischer * this holds all the stuff that should be done at load time 129a8353960SJulian Elischer */ 130a8353960SJulian Elischer static int 131a8353960SJulian Elischer ng_device_mod_event(module_t mod, int event, void *data) 132a8353960SJulian Elischer { 133a8353960SJulian Elischer int error = 0; 134a8353960SJulian Elischer 135a8353960SJulian Elischer #ifdef NGD_DEBUG 136a8353960SJulian Elischer printf("%s()\n",__func__); 137a8353960SJulian Elischer #endif /* NGD_DEBUG */ 138a8353960SJulian Elischer 139a8353960SJulian Elischer switch (event) { 140a8353960SJulian Elischer case MOD_LOAD: 141a8353960SJulian Elischer 142a8353960SJulian Elischer ng_device_init(); 143a8353960SJulian Elischer break; 144a8353960SJulian Elischer 145a8353960SJulian Elischer case MOD_UNLOAD: 146a8353960SJulian Elischer /* XXX do we need to do something specific ? */ 147a8353960SJulian Elischer /* ng_device_breakdown */ 148a8353960SJulian Elischer break; 149a8353960SJulian Elischer 150a8353960SJulian Elischer default: 151a8353960SJulian Elischer error = EOPNOTSUPP; 152a8353960SJulian Elischer break; 153a8353960SJulian Elischer } 154a8353960SJulian Elischer 155a8353960SJulian Elischer return(error); 156a8353960SJulian Elischer } 157a8353960SJulian Elischer 158a8353960SJulian Elischer 159a8353960SJulian Elischer static int 160a8353960SJulian Elischer ng_device_init() 161a8353960SJulian Elischer { 162a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 163a8353960SJulian Elischer 164a8353960SJulian Elischer #ifdef NGD_DEBUG 165a8353960SJulian Elischer printf("%s()\n",__func__); 166a8353960SJulian Elischer #endif /* NGD_DEBUG */ 167a8353960SJulian Elischer 168a8353960SJulian Elischer SLIST_INIT(&sc->head); 169a8353960SJulian Elischer 170a8353960SJulian Elischer if (ng_make_node_common(&typestruct, &sc->node) != 0) { 171a8353960SJulian Elischer printf("%s(): ng_make_node_common failed\n",__func__); 172a8353960SJulian Elischer return(ENXIO); 173a8353960SJulian Elischer } 174a8353960SJulian Elischer sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE); 175a8353960SJulian Elischer if (ng_name_node(sc->node, sc->nodename)) { 176a8353960SJulian Elischer NG_NODE_UNREF(sc->node); /* make it go away again */ 177a8353960SJulian Elischer printf("%s(): ng_name_node failed\n",__func__); 178a8353960SJulian Elischer return(ENXIO); 179a8353960SJulian Elischer } 180a8353960SJulian Elischer NG_NODE_SET_PRIVATE(sc->node, sc); 181a8353960SJulian Elischer 182a8353960SJulian Elischer return(0); 183a8353960SJulian Elischer } 184a8353960SJulian Elischer 185a8353960SJulian Elischer /* 186a8353960SJulian Elischer * don't allow to be created, only the device can do that 187a8353960SJulian Elischer */ 188a8353960SJulian Elischer static int 189a8353960SJulian Elischer ng_device_cons(node_p node) 190a8353960SJulian Elischer { 191a8353960SJulian Elischer 192a8353960SJulian Elischer #ifdef NGD_DEBUG 193a8353960SJulian Elischer printf("%s()\n",__func__); 194a8353960SJulian Elischer #endif /* NGD_DEBUG */ 195a8353960SJulian Elischer 196a8353960SJulian Elischer return(EINVAL); 197a8353960SJulian Elischer } 198a8353960SJulian Elischer 199a8353960SJulian Elischer /* 200a8353960SJulian Elischer * Receive control message. We just bounce it back as a reply. 201a8353960SJulian Elischer */ 202a8353960SJulian Elischer static int 203a8353960SJulian Elischer ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook) 204a8353960SJulian Elischer { 205a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 206a8353960SJulian Elischer struct ng_mesg *msg; 207a8353960SJulian Elischer int error = 0; 208a8353960SJulian Elischer struct ngd_connection * connection = NULL; 209a8353960SJulian Elischer struct ngd_connection *tmp = NULL; 210a8353960SJulian Elischer 211a8353960SJulian Elischer #ifdef NGD_DEBUG 212a8353960SJulian Elischer printf("%s()\n",__func__); 213a8353960SJulian Elischer #endif /* NGD_DEBUG */ 214a8353960SJulian Elischer 215a8353960SJulian Elischer NGI_GET_MSG(item, msg); 216a8353960SJulian Elischer 217a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 218a8353960SJulian Elischer if(tmp->active_hook == lasthook) { 219a8353960SJulian Elischer connection = tmp; 220a8353960SJulian Elischer } 221a8353960SJulian Elischer } 222a8353960SJulian Elischer if(connection == NULL) { 223a8353960SJulian Elischer printf("%s(): connection is still NULL, no hook found\n",__func__); 224a8353960SJulian Elischer return(-1); 225a8353960SJulian Elischer } 226a8353960SJulian Elischer 227a8353960SJulian Elischer return(error); 228a8353960SJulian Elischer } 229a8353960SJulian Elischer 230a8353960SJulian Elischer static int 231a8353960SJulian Elischer get_free_unit() 232a8353960SJulian Elischer { 233a8353960SJulian Elischer struct ngd_connection *tmp = NULL; 234a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 235a8353960SJulian Elischer int n = 0; 236a8353960SJulian Elischer int unit = -1; 237a8353960SJulian Elischer 238a8353960SJulian Elischer #ifdef NGD_DEBUG 239a8353960SJulian Elischer printf("%s()\n",__func__); 240a8353960SJulian Elischer #endif /* NGD_DEBUG */ 241a8353960SJulian Elischer 242a8353960SJulian Elischer /* When there is no list yet, the first device unit is always 0. */ 243a8353960SJulian Elischer if SLIST_EMPTY(&sc->head) { 244a8353960SJulian Elischer unit = 0; 245a8353960SJulian Elischer return(unit); 246a8353960SJulian Elischer } 247a8353960SJulian Elischer 248a8353960SJulian Elischer /* Just do a brute force loop to find the first free unit that is 249a8353960SJulian Elischer * smaller than MAX_NGD. 250a8353960SJulian Elischer * Set MAX_NGD to a large value, doesn't impact performance. 251a8353960SJulian Elischer */ 252a8353960SJulian Elischer for(n = 0;n<MAX_NGD && unit == -1;n++) { 253a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 254a8353960SJulian Elischer 255a8353960SJulian Elischer if(tmp->unit == n) { 256a8353960SJulian Elischer unit = -1; 257a8353960SJulian Elischer break; 258a8353960SJulian Elischer } 259a8353960SJulian Elischer unit = n; 260a8353960SJulian Elischer } 261a8353960SJulian Elischer } 262a8353960SJulian Elischer 263a8353960SJulian Elischer return(unit); 264a8353960SJulian Elischer } 265a8353960SJulian Elischer 266a8353960SJulian Elischer /* 267a8353960SJulian Elischer * incoming hook 268a8353960SJulian Elischer */ 269a8353960SJulian Elischer static int 270a8353960SJulian Elischer ng_device_newhook(node_p node, hook_p hook, const char *name) 271a8353960SJulian Elischer { 272a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 273a8353960SJulian Elischer struct ngd_connection * new_connection = NULL; 274a8353960SJulian Elischer 275a8353960SJulian Elischer #ifdef NGD_DEBUG 276a8353960SJulian Elischer printf("%s()\n",__func__); 277a8353960SJulian Elischer #endif /* NGD_DEBUG */ 278a8353960SJulian Elischer 279a8353960SJulian Elischer new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT); 280a8353960SJulian Elischer if(new_connection == NULL) { 281a8353960SJulian Elischer printf("%s(): ERROR: new_connection == NULL\n",__func__); 282a8353960SJulian Elischer return(-1); 283a8353960SJulian Elischer } 284a8353960SJulian Elischer 285a8353960SJulian Elischer new_connection->unit = get_free_unit(); 286a8353960SJulian Elischer if(new_connection->unit<0) { 287a8353960SJulian Elischer printf("%s: No free unit found by get_free_unit(), " 288a8353960SJulian Elischer "increas MAX_NGD\n",__func__); 289a8353960SJulian Elischer return(-1); 290a8353960SJulian Elischer } 291a8353960SJulian Elischer new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit); 292a8353960SJulian Elischer if(new_connection->ngddev == NULL) { 293a8353960SJulian Elischer printf("%s(): make_dev failed\n",__func__); 294a8353960SJulian Elischer return(-1); 295a8353960SJulian Elischer } 296a8353960SJulian Elischer 297a8353960SJulian Elischer new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO); 298a8353960SJulian Elischer if(new_connection->readq == NULL) { 299a8353960SJulian Elischer printf("%s(): readq malloc failed\n",__func__); 300a8353960SJulian Elischer return(-1); 301a8353960SJulian Elischer } 302a8353960SJulian Elischer 303a8353960SJulian Elischer /* point to begin of buffer */ 304a8353960SJulian Elischer new_connection->loc = 0; 305a8353960SJulian Elischer new_connection->active_hook = hook; 306a8353960SJulian Elischer 307a8353960SJulian Elischer SLIST_INSERT_HEAD(&sc->head, new_connection, links); 308a8353960SJulian Elischer 309a8353960SJulian Elischer return(0); 310a8353960SJulian Elischer } 311a8353960SJulian Elischer 312a8353960SJulian Elischer /* 313a8353960SJulian Elischer * we gave ok to a new hook 314a8353960SJulian Elischer * now connect 315a8353960SJulian Elischer */ 316a8353960SJulian Elischer static int 317a8353960SJulian Elischer ng_device_connect(hook_p hook) 318a8353960SJulian Elischer { 319a8353960SJulian Elischer 320a8353960SJulian Elischer #ifdef NGD_DEBUG 321a8353960SJulian Elischer printf("%s()\n",__func__); 322a8353960SJulian Elischer #endif /* NGD_DEBUG */ 323a8353960SJulian Elischer 324a8353960SJulian Elischer return(0); 325a8353960SJulian Elischer } 326a8353960SJulian Elischer 327a8353960SJulian Elischer 328a8353960SJulian Elischer /* 329a8353960SJulian Elischer * Receive data from hook 330a8353960SJulian Elischer */ 331a8353960SJulian Elischer static int 332a8353960SJulian Elischer ng_device_rcvdata(hook_p hook, item_p item) 333a8353960SJulian Elischer { 334a8353960SJulian Elischer struct mbuf *m; 335a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 336a8353960SJulian Elischer struct ngd_connection * connection = NULL; 337a8353960SJulian Elischer struct ngd_connection * tmp; 338a8353960SJulian Elischer char *buffer; 339a8353960SJulian Elischer 340a8353960SJulian Elischer #ifdef NGD_DEBUG 341a8353960SJulian Elischer printf("%s()\n",__func__); 342a8353960SJulian Elischer #endif /* NGD_DEBUG */ 343a8353960SJulian Elischer 344a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 345a8353960SJulian Elischer if(tmp->active_hook == hook) { 346a8353960SJulian Elischer connection = tmp; 347a8353960SJulian Elischer } 348a8353960SJulian Elischer } 349a8353960SJulian Elischer if(connection == NULL) { 350a8353960SJulian Elischer printf("%s(): connection is still NULL, no hook found\n",__func__); 351a8353960SJulian Elischer return(-1); 352a8353960SJulian Elischer } 353a8353960SJulian Elischer 354a8353960SJulian Elischer NGI_GET_M(item, m); 355a8353960SJulian Elischer NG_FREE_ITEM(item); 356a8353960SJulian Elischer 357a8353960SJulian Elischer m = m_pullup(m,m->m_len); 358a8353960SJulian Elischer if(m == NULL) { 359a8353960SJulian Elischer printf("%s(): ERROR: m_pullup failed\n",__func__); 360a8353960SJulian Elischer return(-1); 361a8353960SJulian Elischer } 362a8353960SJulian Elischer 363a8353960SJulian Elischer buffer = malloc(sizeof(char)*m->m_len, M_DEVBUF, M_NOWAIT | M_ZERO); 364a8353960SJulian Elischer if(buffer == NULL) { 365a8353960SJulian Elischer printf("%s(): ERROR: buffer malloc failed\n",__func__); 366a8353960SJulian Elischer return(-1); 367a8353960SJulian Elischer } 368a8353960SJulian Elischer 369a8353960SJulian Elischer buffer = mtod(m,char *); 370a8353960SJulian Elischer 371a8353960SJulian Elischer if( (connection->loc+m->m_len) < NGD_QUEUE_SIZE) { 372a8353960SJulian Elischer memcpy(connection->readq+connection->loc, buffer, m->m_len); 373a8353960SJulian Elischer connection->loc += m->m_len; 374a8353960SJulian Elischer } else 375a8353960SJulian Elischer printf("%s(): queue full, first read out a bit\n",__func__); 376a8353960SJulian Elischer 377a8353960SJulian Elischer free(buffer,M_DEVBUF); 378a8353960SJulian Elischer 379a8353960SJulian Elischer return(0); 380a8353960SJulian Elischer } 381a8353960SJulian Elischer 382a8353960SJulian Elischer /* 383a8353960SJulian Elischer * Removal of the last link destroys the node 384a8353960SJulian Elischer */ 385a8353960SJulian Elischer static int 386a8353960SJulian Elischer ng_device_disconnect(hook_p hook) 387a8353960SJulian Elischer { 388a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 389a8353960SJulian Elischer struct ngd_connection * connection = NULL; 390a8353960SJulian Elischer struct ngd_connection * tmp; 391a8353960SJulian Elischer 392a8353960SJulian Elischer #ifdef NGD_DEBUG 393a8353960SJulian Elischer printf("%s()\n",__func__); 394a8353960SJulian Elischer #endif /* NGD_DEBUG */ 395a8353960SJulian Elischer 396a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 397a8353960SJulian Elischer if(tmp->active_hook == hook) { 398a8353960SJulian Elischer connection = tmp; 399a8353960SJulian Elischer } 400a8353960SJulian Elischer } 401a8353960SJulian Elischer if(connection == NULL) { 402a8353960SJulian Elischer printf("%s(): connection is still NULL, no hook found\n",__func__); 403a8353960SJulian Elischer return(-1); 404a8353960SJulian Elischer } 405a8353960SJulian Elischer 406a8353960SJulian Elischer free(connection->readq,M_DEVBUF); 407a8353960SJulian Elischer 408a8353960SJulian Elischer destroy_dev(connection->ngddev); 409a8353960SJulian Elischer 410a8353960SJulian Elischer SLIST_REMOVE(&sc->head,connection,ngd_connection,links); 411a8353960SJulian Elischer 412a8353960SJulian Elischer return(0); 413a8353960SJulian Elischer } 414a8353960SJulian Elischer /* 415a8353960SJulian Elischer * the device is opened 416a8353960SJulian Elischer */ 417a8353960SJulian Elischer static int 418a8353960SJulian Elischer ngdopen(dev_t dev, int flag, int mode, struct thread *td) 419a8353960SJulian Elischer { 420a8353960SJulian Elischer 421a8353960SJulian Elischer #ifdef NGD_DEBUG 422a8353960SJulian Elischer printf("%s()\n",__func__); 423a8353960SJulian Elischer #endif /* NGD_DEBUG */ 424a8353960SJulian Elischer 425a8353960SJulian Elischer return(0); 426a8353960SJulian Elischer } 427a8353960SJulian Elischer 428a8353960SJulian Elischer /* 429a8353960SJulian Elischer * the device is closed 430a8353960SJulian Elischer */ 431a8353960SJulian Elischer static int 432a8353960SJulian Elischer ngdclose(dev_t dev, int flag, int mode, struct thread *td) 433a8353960SJulian Elischer { 434a8353960SJulian Elischer 435a8353960SJulian Elischer #ifdef NGD_DEBUG 436a8353960SJulian Elischer printf("%s()\n",__func__); 437a8353960SJulian Elischer #endif 438a8353960SJulian Elischer 439a8353960SJulian Elischer return(0); 440a8353960SJulian Elischer } 441a8353960SJulian Elischer 442a8353960SJulian Elischer 443a8353960SJulian Elischer /* 444a8353960SJulian Elischer * process ioctl 445a8353960SJulian Elischer * 446a8353960SJulian Elischer * they are translated into netgraph messages and passed on 447a8353960SJulian Elischer * 448a8353960SJulian Elischer */ 449a8353960SJulian Elischer static int 450a8353960SJulian Elischer ngdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 451a8353960SJulian Elischer { 452a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 453a8353960SJulian Elischer struct ngd_connection * connection = NULL; 454a8353960SJulian Elischer struct ngd_connection * tmp; 455a8353960SJulian Elischer int error = 0; 456a8353960SJulian Elischer struct ng_mesg *msg; 457a8353960SJulian Elischer struct ngd_param_s * datap; 458a8353960SJulian Elischer 459a8353960SJulian Elischer #ifdef NGD_DEBUG 460a8353960SJulian Elischer printf("%s()\n",__func__); 461a8353960SJulian Elischer #endif /* NGD_DEBUG */ 462a8353960SJulian Elischer 463a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 464a8353960SJulian Elischer if(tmp->ngddev == dev) { 465a8353960SJulian Elischer connection = tmp; 466a8353960SJulian Elischer } 467a8353960SJulian Elischer } 468a8353960SJulian Elischer if(connection == NULL) { 469a8353960SJulian Elischer printf("%s(): connection is still NULL, no dev found\n",__func__); 470a8353960SJulian Elischer return(-1); 471a8353960SJulian Elischer } 472a8353960SJulian Elischer 473a8353960SJulian Elischer /* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */ 474a8353960SJulian Elischer NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s), 475a8353960SJulian Elischer M_NOWAIT); 476a8353960SJulian Elischer if (msg == NULL) { 477a8353960SJulian Elischer printf("%s(): msg == NULL\n",__func__); 478a8353960SJulian Elischer goto nomsg; 479a8353960SJulian Elischer } 480a8353960SJulian Elischer 481a8353960SJulian Elischer /* pass the ioctl data into the ->data area */ 482a8353960SJulian Elischer datap = (struct ngd_param_s *)msg->data; 483a8353960SJulian Elischer datap->p = addr; 484a8353960SJulian Elischer 485a8353960SJulian Elischer /* NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr) */ 486a8353960SJulian Elischer NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, NULL); 487a8353960SJulian Elischer if(error) 488a8353960SJulian Elischer printf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error); 489a8353960SJulian Elischer 490a8353960SJulian Elischer nomsg: 491a8353960SJulian Elischer 492a8353960SJulian Elischer return(0); 493a8353960SJulian Elischer } 494a8353960SJulian Elischer 495a8353960SJulian Elischer 496a8353960SJulian Elischer /* 497a8353960SJulian Elischer * This function is called when a read(2) is done to our device. 498a8353960SJulian Elischer * We pass the data available in kernelspace on into userland using 499a8353960SJulian Elischer * uiomove. 500a8353960SJulian Elischer */ 501a8353960SJulian Elischer static int 502a8353960SJulian Elischer ngdread(dev_t dev, struct uio *uio, int flag) 503a8353960SJulian Elischer { 504a8353960SJulian Elischer int ret = 0, amnt; 505a8353960SJulian Elischer char buffer[uio->uio_resid+1]; 506a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 507a8353960SJulian Elischer struct ngd_connection * connection = NULL; 508a8353960SJulian Elischer struct ngd_connection * tmp; 509a8353960SJulian Elischer 510a8353960SJulian Elischer #ifdef NGD_DEBUG 511a8353960SJulian Elischer printf("%s()\n",__func__); 512a8353960SJulian Elischer #endif /* NGD_DEBUG */ 513a8353960SJulian Elischer 514a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 515a8353960SJulian Elischer if(tmp->ngddev == dev) { 516a8353960SJulian Elischer connection = tmp; 517a8353960SJulian Elischer } 518a8353960SJulian Elischer } 519a8353960SJulian Elischer if(connection == NULL) { 520a8353960SJulian Elischer printf("%s(): connection is still NULL, no dev found\n",__func__); 521a8353960SJulian Elischer return(-1); 522a8353960SJulian Elischer } 523a8353960SJulian Elischer 524a8353960SJulian Elischer while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) { 525a8353960SJulian Elischer amnt = MIN(uio->uio_resid,connection->loc); 526a8353960SJulian Elischer 527a8353960SJulian Elischer memcpy(buffer,connection->readq, amnt); 528a8353960SJulian Elischer memcpy(connection->readq, connection->readq+amnt, 529a8353960SJulian Elischer connection->loc-amnt); 530a8353960SJulian Elischer connection->loc -= amnt; 531a8353960SJulian Elischer 532a8353960SJulian Elischer ret = uiomove((caddr_t)buffer, amnt, uio); 533a8353960SJulian Elischer if(ret != 0) 534a8353960SJulian Elischer goto error; 535a8353960SJulian Elischer 536a8353960SJulian Elischer } 537a8353960SJulian Elischer return(0); 538a8353960SJulian Elischer 539a8353960SJulian Elischer error: 540a8353960SJulian Elischer printf("%s(): uiomove returns error %d\n",__func__,ret); 541a8353960SJulian Elischer /* do error cleanup here */ 542a8353960SJulian Elischer return(ret); 543a8353960SJulian Elischer } 544a8353960SJulian Elischer 545a8353960SJulian Elischer 546a8353960SJulian Elischer /* 547a8353960SJulian Elischer * This function is called when our device is written to. 548a8353960SJulian Elischer * We read the data from userland into our local buffer and pass it on 549a8353960SJulian Elischer * into the remote hook. 550a8353960SJulian Elischer * 551a8353960SJulian Elischer */ 552a8353960SJulian Elischer static int 553a8353960SJulian Elischer ngdwrite(dev_t dev, struct uio *uio, int flag) 554a8353960SJulian Elischer { 555a8353960SJulian Elischer int ret; 556a8353960SJulian Elischer int error = 0; 557a8353960SJulian Elischer struct mbuf *m; 558a8353960SJulian Elischer char buffer[uio->uio_resid]; 559a8353960SJulian Elischer int len = uio->uio_resid; 560a8353960SJulian Elischer struct ngd_softc *sc =& ngd_softc; 561a8353960SJulian Elischer struct ngd_connection * connection = NULL; 562a8353960SJulian Elischer struct ngd_connection * tmp; 563a8353960SJulian Elischer 564a8353960SJulian Elischer #ifdef NGD_DEBUG 565a8353960SJulian Elischer printf("%s()\n",__func__); 566a8353960SJulian Elischer #endif /* NGD_DEBUG */ 567a8353960SJulian Elischer 568a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 569a8353960SJulian Elischer if(tmp->ngddev == dev) { 570a8353960SJulian Elischer connection = tmp; 571a8353960SJulian Elischer } 572a8353960SJulian Elischer } 573a8353960SJulian Elischer 574a8353960SJulian Elischer if(connection == NULL) { 575a8353960SJulian Elischer printf("%s(): connection is still NULL, no dev found\n",__func__); 576a8353960SJulian Elischer return(-1); 577a8353960SJulian Elischer } 578a8353960SJulian Elischer 579a8353960SJulian Elischer if (len > 0) { 580a8353960SJulian Elischer if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0) 581a8353960SJulian Elischer goto error; 582a8353960SJulian Elischer } else 583a8353960SJulian Elischer printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__); 584a8353960SJulian Elischer 585a8353960SJulian Elischer m = m_devget(buffer,len,0,NULL,NULL); 586a8353960SJulian Elischer 587a8353960SJulian Elischer NG_SEND_DATA_ONLY(error,connection->active_hook,m); 588a8353960SJulian Elischer 589a8353960SJulian Elischer return(0); 590a8353960SJulian Elischer 591a8353960SJulian Elischer error: 592a8353960SJulian Elischer /* do error cleanup here */ 593a8353960SJulian Elischer printf("%s(): uiomove returned err: %d\n",__func__,ret); 594a8353960SJulian Elischer 595a8353960SJulian Elischer return(ret); 596a8353960SJulian Elischer } 597a8353960SJulian Elischer 598a8353960SJulian Elischer /* 599a8353960SJulian Elischer * we are being polled/selected 600a8353960SJulian Elischer * check if there is data available for read 601a8353960SJulian Elischer */ 602a8353960SJulian Elischer static int 603a8353960SJulian Elischer ngdpoll(dev_t dev, int events, struct thread *td) 604a8353960SJulian Elischer { 605a8353960SJulian Elischer int revents = 0; 606a8353960SJulian Elischer struct ngd_softc *sc = &ngd_softc; 607a8353960SJulian Elischer struct ngd_connection * connection = NULL; 608a8353960SJulian Elischer struct ngd_connection * tmp; 609a8353960SJulian Elischer 610a8353960SJulian Elischer 611a8353960SJulian Elischer if (events & (POLLIN | POLLRDNORM)) { 612a8353960SJulian Elischer /* get the connection we have to know the loc from */ 613a8353960SJulian Elischer SLIST_FOREACH(tmp,&sc->head,links) { 614a8353960SJulian Elischer if(tmp->ngddev == dev) { 615a8353960SJulian Elischer connection = tmp; 616a8353960SJulian Elischer } 617a8353960SJulian Elischer } 618a8353960SJulian Elischer if(connection == NULL) { 619a8353960SJulian Elischer printf("%s(): ERROR: connection is still NULL," 620a8353960SJulian Elischer "no dev found\n",__func__); 621a8353960SJulian Elischer return(-1); 622a8353960SJulian Elischer } 623a8353960SJulian Elischer 624a8353960SJulian Elischer if (connection->loc > 0) 625a8353960SJulian Elischer revents |= events & (POLLIN | POLLRDNORM); 626a8353960SJulian Elischer } 627a8353960SJulian Elischer 628a8353960SJulian Elischer return(revents); 629a8353960SJulian Elischer } 630