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