1 /*- 2 * Copyright (c) 2002 Mark Santcroos <marks@ripe.net> 3 * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * Netgraph "device" node 26 * 27 * This node presents a /dev/ngd%d device that interfaces to an other 28 * netgraph node. 29 * 30 * $FreeBSD: src/sys/netgraph/ng_device.c,v 1.22 2006/11/02 17:37:21 andre Exp $ 31 * 32 */ 33 34 #if 0 35 #define DBG do { kprintf("ng_device: %s\n", __func__ ); } while (0) 36 #else 37 #define DBG do {} while (0) 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/mbuf.h> 45 #include <sys/poll.h> 46 #include <sys/queue.h> 47 #include <sys/socket.h> 48 #include <sys/systm.h> 49 #include <sys/uio.h> 50 #include <sys/vnode.h> 51 52 #include <net/if.h> 53 #include <net/if_var.h> 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 58 #include "ng_message.h" 59 #include "netgraph.h" 60 #include "ng_device.h" 61 62 #define ERROUT(x) do { error = (x); goto done; } while (0) 63 64 /* Netgraph methods */ 65 static int ng_device_mod_event(module_t, int, void *); 66 static ng_constructor_t ng_device_constructor; 67 static ng_rcvmsg_t ng_device_rcvmsg; 68 static ng_shutdown_t ng_device_shutdown; 69 static ng_newhook_t ng_device_newhook; 70 static ng_rcvdata_t ng_device_rcvdata; 71 static ng_disconnect_t ng_device_disconnect; 72 73 /* Netgraph type */ 74 static struct ng_type ngd_typestruct = { 75 .version = NG_ABI_VERSION, 76 .name = NG_DEVICE_NODE_TYPE, 77 .mod_event = ng_device_mod_event, 78 .constructor = ng_device_constructor, 79 .rcvmsg = ng_device_rcvmsg, 80 .shutdown = ng_device_shutdown, 81 .newhook = ng_device_newhook, 82 .rcvdata = ng_device_rcvdata, 83 .disconnect = ng_device_disconnect, 84 }; 85 NETGRAPH_INIT(device, &ngd_typestruct); 86 87 /* per node data */ 88 struct ngd_private { 89 struct ifqueue readq; 90 struct ng_node *node; 91 struct ng_hook *hook; 92 struct cdev *ngddev; 93 struct mtx ngd_mtx; 94 int unit; 95 uint16_t flags; 96 #define NGDF_OPEN 0x0001 97 #define NGDF_RWAIT 0x0002 98 }; 99 typedef struct ngd_private *priv_p; 100 101 /* unit number allocator entity */ 102 static struct unrhdr *ngd_unit; 103 104 /* Maximum number of NGD devices */ 105 #define MAX_NGD 999 106 107 static d_close_t ngdclose; 108 static d_open_t ngdopen; 109 static d_read_t ngdread; 110 static d_write_t ngdwrite; 111 #if 0 112 static d_ioctl_t ngdioctl; 113 #endif 114 static d_poll_t ngdpoll; 115 116 static struct cdevsw ngd_cdevsw = { 117 .d_version = D_VERSION, 118 .d_open = ngdopen, 119 .d_close = ngdclose, 120 .d_read = ngdread, 121 .d_write = ngdwrite, 122 #if 0 123 .d_ioctl = ngdioctl, 124 #endif 125 .d_poll = ngdpoll, 126 .d_name = NG_DEVICE_DEVNAME, 127 }; 128 129 /****************************************************************************** 130 * Netgraph methods 131 ******************************************************************************/ 132 133 /* 134 * Handle loading and unloading for this node type. 135 */ 136 static int 137 ng_device_mod_event(module_t mod, int event, void *data) 138 { 139 int error = 0; 140 141 switch (event) { 142 case MOD_LOAD: 143 ngd_unit = new_unrhdr(0, MAX_NGD, NULL); 144 break; 145 case MOD_UNLOAD: 146 delete_unrhdr(ngd_unit); 147 break; 148 default: 149 error = EOPNOTSUPP; 150 break; 151 } 152 return (error); 153 } 154 155 /* 156 * create new node 157 */ 158 static int 159 ng_device_constructor(node_p node) 160 { 161 priv_p priv; 162 163 DBG; 164 165 priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 166 167 /* Allocate unit number */ 168 priv->unit = alloc_unr(ngd_unit); 169 170 /* Initialize mutexes and queue */ 171 mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF); 172 mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF); 173 IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen); 174 175 /* Link everything together */ 176 NG_NODE_SET_PRIVATE(node, priv); 177 priv->node = node; 178 179 priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT, 180 GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit); 181 if(priv->ngddev == NULL) { 182 kprintf("%s(): make_dev() failed\n",__func__); 183 mtx_destroy(&priv->ngd_mtx); 184 mtx_destroy(&priv->readq.ifq_mtx); 185 free_unr(ngd_unit, priv->unit); 186 kfree(priv, M_NETGRAPH); 187 return(EINVAL); 188 } 189 /* XXX: race here? */ 190 priv->ngddev->si_drv1 = priv; 191 192 return(0); 193 } 194 195 /* 196 * Process control message. 197 */ 198 199 static int 200 ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook) 201 { 202 const priv_p priv = NG_NODE_PRIVATE(node); 203 struct ng_mesg *msg; 204 struct ng_mesg *resp = NULL; 205 int error = 0; 206 207 NGI_GET_MSG(item, msg); 208 209 if (msg->header.typecookie == NGM_DEVICE_COOKIE) { 210 switch (msg->header.cmd) { 211 case NGM_DEVICE_GET_DEVNAME: 212 /* XXX: Fix when MAX_NGD us bigger */ 213 NG_MKRESPONSE(resp, msg, 214 strlen(NG_DEVICE_DEVNAME) + 4, M_WAITOK); 215 216 if (resp == NULL) 217 ERROUT(ENOMEM); 218 219 strlcpy((char *)resp->data, priv->ngddev->si_name, 220 strlen(priv->ngddev->si_name) + 1); 221 break; 222 223 default: 224 error = EINVAL; 225 break; 226 } 227 } else 228 error = EINVAL; 229 230 done: 231 NG_RESPOND_MSG(error, node, item, resp); 232 NG_FREE_MSG(msg); 233 return (error); 234 } 235 236 /* 237 * Accept incoming hook. We support only one hook per node. 238 */ 239 static int 240 ng_device_newhook(node_p node, hook_p hook, const char *name) 241 { 242 priv_p priv = NG_NODE_PRIVATE(node); 243 244 DBG; 245 246 /* We have only one hook per node */ 247 if (priv->hook != NULL) 248 return (EISCONN); 249 250 priv->hook = hook; 251 252 return(0); 253 } 254 255 /* 256 * Receive data from hook, write it to device. 257 */ 258 static int 259 ng_device_rcvdata(hook_p hook, item_p item) 260 { 261 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 262 struct mbuf *m; 263 264 DBG; 265 266 NGI_GET_M(item, m); 267 NG_FREE_ITEM(item); 268 269 IF_LOCK(&priv->readq); 270 if (_IF_QFULL(&priv->readq)) { 271 _IF_DROP(&priv->readq); 272 IF_UNLOCK(&priv->readq); 273 NG_FREE_M(m); 274 return (ENOBUFS); 275 } 276 277 _IF_ENQUEUE(&priv->readq, m); 278 IF_UNLOCK(&priv->readq); 279 mtx_lock(&priv->ngd_mtx); 280 if (priv->flags & NGDF_RWAIT) { 281 priv->flags &= ~NGDF_RWAIT; 282 wakeup(priv); 283 } 284 mtx_unlock(&priv->ngd_mtx); 285 286 return(0); 287 } 288 289 /* 290 * Removal of the hook destroys the node. 291 */ 292 static int 293 ng_device_disconnect(hook_p hook) 294 { 295 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 296 297 DBG; 298 299 destroy_dev(priv->ngddev); 300 mtx_destroy(&priv->ngd_mtx); 301 302 IF_DRAIN(&priv->readq); 303 mtx_destroy(&(priv)->readq.ifq_mtx); 304 305 free_unr(ngd_unit, priv->unit); 306 307 kfree(priv, M_NETGRAPH); 308 309 ng_rmnode_self(NG_HOOK_NODE(hook)); 310 311 return(0); 312 } 313 314 /* 315 * Node shutdown. Everything is already done in disconnect method. 316 */ 317 static int 318 ng_device_shutdown(node_p node) 319 { 320 NG_NODE_UNREF(node); 321 return (0); 322 } 323 324 /****************************************************************************** 325 * Device methods 326 ******************************************************************************/ 327 328 /* 329 * the device is opened 330 */ 331 static int 332 ngdopen(struct cdev *dev, int flag, int mode, struct thread *td) 333 { 334 priv_p priv = (priv_p )dev->si_drv1; 335 336 DBG; 337 338 mtx_lock(&priv->ngd_mtx); 339 priv->flags |= NGDF_OPEN; 340 mtx_unlock(&priv->ngd_mtx); 341 342 return(0); 343 } 344 345 /* 346 * the device is closed 347 */ 348 static int 349 ngdclose(struct cdev *dev, int flag, int mode, struct thread *td) 350 { 351 priv_p priv = (priv_p )dev->si_drv1; 352 353 DBG; 354 mtx_lock(&priv->ngd_mtx); 355 priv->flags &= ~NGDF_OPEN; 356 mtx_unlock(&priv->ngd_mtx); 357 358 return(0); 359 } 360 361 #if 0 /* 362 * The ioctl is transformed into netgraph control message. 363 * We do not process them, yet. 364 */ 365 /* 366 * process ioctl 367 * 368 * they are translated into netgraph messages and passed on 369 * 370 */ 371 static int 372 ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 373 { 374 struct ngd_softc *sc = &ngd_softc; 375 struct ngd_connection * connection = NULL; 376 struct ngd_connection * tmp; 377 int error = 0; 378 struct ng_mesg *msg; 379 struct ngd_param_s * datap; 380 381 DBG; 382 383 NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s), 384 M_WAITOK); 385 if (msg == NULL) { 386 kprintf("%s(): msg == NULL\n",__func__); 387 goto nomsg; 388 } 389 390 /* pass the ioctl data into the ->data area */ 391 datap = (struct ngd_param_s *)msg->data; 392 datap->p = addr; 393 394 NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0); 395 if(error) 396 kprintf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error); 397 398 nomsg: 399 400 return(0); 401 } 402 #endif /* if 0 */ 403 404 /* 405 * This function is called when a read(2) is done to our device. 406 * We process one mbuf from queue. 407 */ 408 static int 409 ngdread(struct cdev *dev, struct uio *uio, int flag) 410 { 411 priv_p priv = (priv_p )dev->si_drv1; 412 struct mbuf *m; 413 int len, error = 0; 414 415 DBG; 416 417 /* get an mbuf */ 418 do { 419 IF_DEQUEUE(&priv->readq, m); 420 if (m == NULL) { 421 if (flag & IO_NDELAY) 422 return (EWOULDBLOCK); 423 mtx_lock(&priv->ngd_mtx); 424 priv->flags |= NGDF_RWAIT; 425 if ((error = msleep(priv, &priv->ngd_mtx, 426 PDROP | PCATCH | (PZERO + 1), 427 "ngdread", 0)) != 0) 428 return (error); 429 } 430 } while (m == NULL); 431 432 while (m && uio->uio_resid > 0 && error == 0) { 433 len = MIN(uio->uio_resid, m->m_len); 434 if (len != 0) 435 error = uiomove(mtod(m, void *), len, uio); 436 m = m_free(m); 437 } 438 439 if (m) 440 m_freem(m); 441 442 return (error); 443 } 444 445 446 /* 447 * This function is called when our device is written to. 448 * We read the data from userland into mbuf chain and pass it to the remote hook. 449 * 450 */ 451 static int 452 ngdwrite(struct cdev *dev, struct uio *uio, int flag) 453 { 454 priv_p priv = (priv_p )dev->si_drv1; 455 struct mbuf *m; 456 int error = 0; 457 458 DBG; 459 460 if (uio->uio_resid == 0) 461 return (0); 462 463 if (uio->uio_resid > IP_MAXPACKET) 464 return (EIO); 465 466 if ((m = m_uiotombuf(uio, M_NOWAIT, 0, 0, M_PKTHDR)) == NULL) 467 return (ENOBUFS); 468 469 NG_SEND_DATA_ONLY(error, priv->hook, m); 470 471 return (error); 472 } 473 474 /* 475 * we are being polled/selected 476 * check if there is data available for read 477 */ 478 static int 479 ngdpoll(struct cdev *dev, int events, struct thread *td) 480 { 481 priv_p priv = (priv_p )dev->si_drv1; 482 int revents = 0; 483 484 if (events & (POLLIN | POLLRDNORM) && 485 !IFQ_IS_EMPTY(&priv->readq)) 486 revents |= events & (POLLIN | POLLRDNORM); 487 488 return (revents); 489 } 490