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 * Copyright (c) 2025 Quentin Thébault <quentin.thebault@defenso.fr>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Netgraph "device" node
29 *
30 * This node presents a /dev/ngd%d device that interfaces to an other
31 * netgraph node.
32 *
33 */
34
35 #if 0
36 #define DBG do { printf("ng_device: %s\n", __func__); } while (0)
37 #else
38 #define DBG do {} while (0)
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/conf.h>
44 #include <sys/epoch.h>
45 #include <sys/fcntl.h>
46 #include <sys/filio.h>
47 #include <sys/ioccom.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.h>
51 #include <sys/poll.h>
52 #include <sys/proc.h>
53 #include <sys/queue.h>
54 #include <sys/selinfo.h>
55 #include <sys/socket.h>
56 #include <sys/syslog.h>
57 #include <sys/uio.h>
58
59 #include <net/ethernet.h>
60 #include <net/if.h>
61 #include <net/if_var.h>
62 #include <netinet/in.h>
63 #include <netinet/in_systm.h>
64 #include <netinet/ip.h>
65
66 #include <netgraph/ng_message.h>
67 #include <netgraph/netgraph.h>
68 #include <netgraph/ng_device.h>
69 #include <netgraph/ng_parse.h>
70
71 #define ERROUT(x) do { error = (x); goto done; } while (0)
72
73 /* Netgraph methods */
74 static int ng_device_mod_event(module_t, int, void *);
75 static ng_constructor_t ng_device_constructor;
76 static ng_rcvmsg_t ng_device_rcvmsg;
77 static ng_shutdown_t ng_device_shutdown;
78 static ng_newhook_t ng_device_newhook;
79 static ng_rcvdata_t ng_device_rcvdata;
80 static ng_disconnect_t ng_device_disconnect;
81
82 /* List of commands and how to convert arguments to/from ASCII. */
83 static const struct ng_cmdlist ng_device_cmds[] = {
84 {
85 NGM_DEVICE_COOKIE,
86 NGM_DEVICE_GET_DEVNAME,
87 "getdevname",
88 NULL,
89 &ng_parse_string_type
90 },
91 {
92 NGM_DEVICE_COOKIE,
93 NGM_DEVICE_ETHERALIGN,
94 "etheralign",
95 NULL,
96 NULL
97 },
98 { 0 }
99 };
100
101 /* Netgraph type */
102 static struct ng_type ngd_typestruct = {
103 .version = NG_ABI_VERSION,
104 .name = NG_DEVICE_NODE_TYPE,
105 .mod_event = ng_device_mod_event,
106 .constructor = ng_device_constructor,
107 .rcvmsg = ng_device_rcvmsg,
108 .shutdown = ng_device_shutdown,
109 .newhook = ng_device_newhook,
110 .rcvdata = ng_device_rcvdata,
111 .disconnect = ng_device_disconnect,
112 .cmdlist = ng_device_cmds,
113 };
114 NETGRAPH_INIT(device, &ngd_typestruct);
115
116 /* per node data */
117 struct ngd_private {
118 struct ifqueue readq;
119 struct ng_node *node;
120 struct ng_hook *hook;
121 struct cdev *ngddev;
122 struct selinfo rsel;
123 struct selinfo wsel;
124 struct mtx ngd_mtx;
125 int unit;
126 int ether_align;
127 uint16_t flags;
128 #define NGDF_OPEN 0x0001
129 #define NGDF_RWAIT 0x0002
130 #define NGDF_DYING 0x0004
131 };
132 typedef struct ngd_private *priv_p;
133
134 /* unit number allocator entity */
135 static struct unrhdr *ngd_unit;
136
137 /* Maximum number of NGD devices */
138 #define MAX_NGD 999
139
140 static d_close_t ngdclose;
141 static d_open_t ngdopen;
142 static d_read_t ngdread;
143 static d_write_t ngdwrite;
144 static d_ioctl_t ngdioctl;
145 static d_poll_t ngdpoll;
146 static d_kqfilter_t ngdkqfilter;
147
148 static int ngd_kqread_event(struct knote *, long);
149 static int ngd_kqwrite_event(struct knote *, long);
150 static void ngd_kqread_detach(struct knote *);
151 static void ngd_kqwrite_detach(struct knote *);
152
153 static const struct filterops ngd_read_filterops = {
154 .f_isfd = 1,
155 .f_detach = ngd_kqread_detach,
156 .f_event = ngd_kqread_event
157 };
158
159 static const struct filterops ngd_write_filterops = {
160 .f_isfd = 1,
161 .f_detach = ngd_kqwrite_detach,
162 .f_event = ngd_kqwrite_event
163 };
164
165 static struct cdevsw ngd_cdevsw = {
166 .d_version = D_VERSION,
167 .d_open = ngdopen,
168 .d_close = ngdclose,
169 .d_read = ngdread,
170 .d_write = ngdwrite,
171 .d_ioctl = ngdioctl,
172 .d_kqfilter = ngdkqfilter,
173 .d_poll = ngdpoll,
174 .d_name = NG_DEVICE_DEVNAME,
175 };
176
177 /*
178 *****************************************************************************
179 * Netgraph methods
180 *****************************************************************************
181 */
182
183 /*
184 * Handle loading and unloading for this node type.
185 */
186 static int
ng_device_mod_event(module_t mod,int event,void * data)187 ng_device_mod_event(module_t mod, int event, void *data)
188 {
189 int error = 0;
190
191 switch (event) {
192 case MOD_LOAD:
193 ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
194 break;
195 case MOD_UNLOAD:
196 delete_unrhdr(ngd_unit);
197 break;
198 default:
199 error = EOPNOTSUPP;
200 break;
201 }
202 return (error);
203 }
204
205 /*
206 * create new node
207 */
208 static int
ng_device_constructor(node_p node)209 ng_device_constructor(node_p node)
210 {
211 priv_p priv;
212
213 DBG;
214
215 priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
216
217 /* Allocate unit number */
218 priv->unit = alloc_unr(ngd_unit);
219
220 /* Initialize mutexes and queue */
221 mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
222 mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
223 IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
224
225 knlist_init_mtx(&priv->rsel.si_note, &priv->ngd_mtx);
226 knlist_init_mtx(&priv->wsel.si_note, &priv->ngd_mtx);
227
228 /* Link everything together */
229 NG_NODE_SET_PRIVATE(node, priv);
230 priv->node = node;
231
232 priv->ngddev = make_dev(&ngd_cdevsw, priv->unit, UID_ROOT,
233 GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
234 if (priv->ngddev == NULL) {
235 printf("%s(): make_dev() failed\n", __func__);
236 knlist_destroy(&priv->rsel.si_note);
237 knlist_destroy(&priv->wsel.si_note);
238 mtx_destroy(&priv->ngd_mtx);
239 mtx_destroy(&priv->readq.ifq_mtx);
240 free_unr(ngd_unit, priv->unit);
241 free(priv, M_NETGRAPH);
242 return (EINVAL);
243 }
244 /* XXX: race here? */
245 priv->ngddev->si_drv1 = priv;
246
247 /* Give this node the same name as the device (if possible). */
248 if (ng_name_node(node, devtoname(priv->ngddev)) != 0)
249 log(LOG_WARNING, "%s: can't acquire netgraph name\n",
250 devtoname(priv->ngddev));
251
252 return (0);
253 }
254
255 /*
256 * Process control message.
257 */
258
259 static int
ng_device_rcvmsg(node_p node,item_p item,hook_p lasthook)260 ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
261 {
262 const priv_p priv = NG_NODE_PRIVATE(node);
263 struct ng_mesg *msg;
264 struct ng_mesg *resp = NULL;
265 const char *dn;
266 int error = 0;
267
268 NGI_GET_MSG(item, msg);
269
270 if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
271 switch (msg->header.cmd) {
272 case NGM_DEVICE_GET_DEVNAME:
273 /* XXX: Fix when MAX_NGD us bigger */
274 NG_MKRESPONSE(resp, msg,
275 strlen(NG_DEVICE_DEVNAME) + 4, M_NOWAIT);
276
277 if (resp == NULL)
278 ERROUT(ENOMEM);
279
280 dn = devtoname(priv->ngddev);
281 strlcpy((char *)resp->data, dn, strlen(dn) + 1);
282 break;
283
284 case NGM_DEVICE_ETHERALIGN:
285 /* Use ETHER_ALIGN on arches that require it. */
286 #ifndef __NO_STRICT_ALIGNMENT
287 priv->ether_align = ETHER_ALIGN;
288 #endif
289 break;
290
291 default:
292 error = EINVAL;
293 break;
294 }
295 } else
296 error = EINVAL;
297
298 done:
299 NG_RESPOND_MSG(error, node, item, resp);
300 NG_FREE_MSG(msg);
301 return (error);
302 }
303
304 /*
305 * Accept incoming hook. We support only one hook per node.
306 */
307 static int
ng_device_newhook(node_p node,hook_p hook,const char * name)308 ng_device_newhook(node_p node, hook_p hook, const char *name)
309 {
310 priv_p priv = NG_NODE_PRIVATE(node);
311
312 DBG;
313
314 /* We have only one hook per node */
315 if (priv->hook != NULL)
316 return (EISCONN);
317
318 priv->hook = hook;
319
320 return (0);
321 }
322
323 /*
324 * Receive data from hook, write it to device.
325 */
326 static int
ng_device_rcvdata(hook_p hook,item_p item)327 ng_device_rcvdata(hook_p hook, item_p item)
328 {
329 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
330 struct mbuf *m;
331
332 DBG;
333
334 NGI_GET_M(item, m);
335 NG_FREE_ITEM(item);
336
337 IF_LOCK(&priv->readq);
338 if (_IF_QFULL(&priv->readq)) {
339 IF_UNLOCK(&priv->readq);
340 NG_FREE_M(m);
341 return (ENOBUFS);
342 }
343
344 _IF_ENQUEUE(&priv->readq, m);
345 IF_UNLOCK(&priv->readq);
346 mtx_lock(&priv->ngd_mtx);
347 if (priv->flags & NGDF_RWAIT) {
348 priv->flags &= ~NGDF_RWAIT;
349 wakeup(priv);
350 }
351 selwakeup(&priv->rsel);
352 KNOTE_LOCKED(&priv->rsel.si_note, 0);
353 mtx_unlock(&priv->ngd_mtx);
354
355 return (0);
356 }
357
358 /*
359 * Removal of the hook destroys the node.
360 */
361 static int
ng_device_disconnect(hook_p hook)362 ng_device_disconnect(hook_p hook)
363 {
364 priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
365
366 DBG;
367
368 mtx_lock(&priv->ngd_mtx);
369 priv->flags |= NGDF_DYING;
370 wakeup(priv);
371 mtx_unlock(&priv->ngd_mtx);
372
373 destroy_dev(priv->ngddev);
374
375 knlist_clear(&priv->rsel.si_note, 0);
376 knlist_clear(&priv->wsel.si_note, 0);
377 knlist_destroy(&priv->rsel.si_note);
378 knlist_destroy(&priv->wsel.si_note);
379 mtx_destroy(&priv->ngd_mtx);
380
381 seldrain(&priv->rsel);
382 seldrain(&priv->wsel);
383
384 IF_DRAIN(&priv->readq);
385 mtx_destroy(&(priv)->readq.ifq_mtx);
386
387 free_unr(ngd_unit, priv->unit);
388
389 free(priv, M_NETGRAPH);
390
391 ng_rmnode_self(NG_HOOK_NODE(hook));
392
393 return (0);
394 }
395
396 /*
397 * Node shutdown. Everything is already done in disconnect method.
398 */
399 static int
ng_device_shutdown(node_p node)400 ng_device_shutdown(node_p node)
401 {
402 NG_NODE_UNREF(node);
403 return (0);
404 }
405
406 /*
407 *****************************************************************************
408 * Device methods
409 *****************************************************************************
410 */
411
412 /*
413 * the device is opened
414 */
415 static int
ngdopen(struct cdev * dev,int flag,int mode,struct thread * td)416 ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
417 {
418 priv_p priv = (priv_p)dev->si_drv1;
419
420 DBG;
421
422 mtx_lock(&priv->ngd_mtx);
423 priv->flags |= NGDF_OPEN;
424 mtx_unlock(&priv->ngd_mtx);
425
426 return (0);
427 }
428
429 /*
430 * the device is closed
431 */
432 static int
ngdclose(struct cdev * dev,int flag,int mode,struct thread * td)433 ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
434 {
435 priv_p priv = (priv_p)dev->si_drv1;
436
437 DBG;
438 mtx_lock(&priv->ngd_mtx);
439 priv->flags &= ~NGDF_OPEN;
440 mtx_unlock(&priv->ngd_mtx);
441
442 return (0);
443 }
444
445 /*
446 * Process IOCTLs
447 *
448 * At this stage we only return success on FIONBIO to allow setting the device
449 * as non-blocking.
450 *
451 */
452 static int
ngdioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)453 ngdioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
454 struct thread *td)
455 {
456 int error;
457
458 switch (cmd) {
459 case FIONBIO:
460 error = 0;
461 break;
462 case FIOASYNC:
463 if (*(int *)data != 0)
464 error = EINVAL;
465 else
466 error = 0;
467 break;
468 default:
469 error = ENOTTY;
470 }
471
472 return (error);
473 }
474
475 #if 0 /*
476 * The ioctl is transformed into netgraph control message.
477 * We do not process them, yet.
478 */
479 /*
480 * process ioctl
481 *
482 * they are translated into netgraph messages and passed on
483 *
484 */
485 static int
486 ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
487 struct thread *td)
488 {
489 struct ngd_softc *sc = &ngd_softc;
490 struct ngd_connection *connection = NULL;
491 struct ngd_connection *tmp;
492 int error = 0;
493 struct ng_mesg *msg;
494 struct ngd_param_s *datap;
495
496 DBG;
497
498 NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
499 M_NOWAIT);
500 if (msg == NULL) {
501 printf("%s(): msg == NULL\n", __func__);
502 goto nomsg;
503 }
504
505 /* pass the ioctl data into the ->data area */
506 datap = (struct ngd_param_s *)msg->data;
507 datap->p = addr;
508
509 NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
510 if (error)
511 printf("%s(): NG_SEND_MSG_HOOK error: %d\n", __func__, error);
512
513 nomsg:
514
515 return (0);
516 }
517 #endif /* if 0 */
518
519 /*
520 * This function is called when a read(2) is done to our device.
521 * We process one mbuf from queue.
522 */
523 static int
ngdread(struct cdev * dev,struct uio * uio,int flag)524 ngdread(struct cdev *dev, struct uio *uio, int flag)
525 {
526 priv_p priv = (priv_p)dev->si_drv1;
527 struct mbuf *m;
528 int len, error = 0;
529
530 DBG;
531
532 /* get an mbuf */
533 do {
534 IF_DEQUEUE(&priv->readq, m);
535 if (m == NULL) {
536 if (flag & O_NONBLOCK)
537 return (EWOULDBLOCK);
538 mtx_lock(&priv->ngd_mtx);
539 priv->flags |= NGDF_RWAIT;
540 if (priv->flags & NGDF_DYING) {
541 mtx_unlock(&priv->ngd_mtx);
542 error = ENXIO;
543 } else
544 error = mtx_sleep(priv, &priv->ngd_mtx,
545 PDROP | PCATCH, "ngdread", 0);
546 if (error != 0)
547 return (error);
548 }
549 } while (m == NULL);
550
551 while (m && uio->uio_resid > 0 && error == 0) {
552 len = MIN(uio->uio_resid, m->m_len);
553 if (len != 0)
554 error = uiomove(mtod(m, void *), len, uio);
555 m = m_free(m);
556 }
557
558 if (m)
559 m_freem(m);
560
561 return (error);
562 }
563
564 /*
565 * This function is called when our device is written to.
566 * We read the data from userland into mbuf chain and pass it to the remote
567 * hook.
568 */
569 static int
ngdwrite(struct cdev * dev,struct uio * uio,int flag)570 ngdwrite(struct cdev *dev, struct uio *uio, int flag)
571 {
572 struct epoch_tracker et;
573 priv_p priv = (priv_p)dev->si_drv1;
574 struct mbuf *m;
575 int error = 0;
576
577 DBG;
578
579 if (uio->uio_resid == 0)
580 return (0);
581
582 if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
583 return (EIO);
584
585 m = m_uiotombuf(uio, M_NOWAIT, 0, priv->ether_align, M_PKTHDR);
586 if (m == NULL)
587 return (ENOBUFS);
588
589 /* Setting VNET is required if connecting to a ng_bridge. */
590 CURVNET_SET(priv->node->nd_vnet);
591 NET_EPOCH_ENTER(et);
592 NG_SEND_DATA_ONLY(error, priv->hook, m);
593 NET_EPOCH_EXIT(et);
594 CURVNET_RESTORE();
595
596 return (error);
597 }
598
599 /*
600 * we are being polled/selected
601 * check if there is data available for read
602 */
603 static int
ngdpoll(struct cdev * dev,int events,struct thread * td)604 ngdpoll(struct cdev *dev, int events, struct thread *td)
605 {
606 priv_p priv = (priv_p)dev->si_drv1;
607 int revents = 0;
608
609 if (events & (POLLIN | POLLRDNORM) &&
610 !IFQ_IS_EMPTY(&priv->readq))
611 revents |= events & (POLLIN | POLLRDNORM);
612
613 return (revents);
614 }
615
616 static void
ngd_kqread_detach(struct knote * kn)617 ngd_kqread_detach(struct knote *kn)
618 {
619 priv_p priv = (priv_p)kn->kn_hook;
620
621 knlist_remove(&priv->rsel.si_note, kn, 0);
622 }
623
624 static int
ngd_kqread_event(struct knote * kn,long hint)625 ngd_kqread_event(struct knote *kn, long hint)
626 {
627 priv_p priv = (priv_p)kn->kn_hook;
628 struct mbuf *m;
629
630 IFQ_LOCK(&priv->readq);
631 if (IFQ_IS_EMPTY(&priv->readq)) {
632 kn->kn_data = 0;
633 } else {
634 /*
635 * Since the queue does not store the total number of bytes that
636 * could be read across all packets and we do not want to
637 * traverse the whole queue, we only report the number of bytes
638 * for the first packet in the queue.
639 */
640 IF_POLL(&priv->readq, m);
641 kn->kn_data = m->m_len;
642 }
643 IFQ_UNLOCK(&priv->readq);
644
645 return (kn->kn_data > 0);
646 }
647
648 static void
ngd_kqwrite_detach(struct knote * kn)649 ngd_kqwrite_detach(struct knote *kn)
650 {
651 priv_p priv = (priv_p)kn->kn_hook;
652
653 knlist_remove(&priv->wsel.si_note, kn, 0);
654 }
655
656 static int
ngd_kqwrite_event(struct knote * kn,long hint)657 ngd_kqwrite_event(struct knote *kn, long hint)
658 {
659 kn->kn_data = IP_MAXPACKET;
660
661 return (1);
662 }
663
664 static int
ngdkqfilter(struct cdev * dev,struct knote * kn)665 ngdkqfilter(struct cdev *dev, struct knote *kn)
666 {
667 priv_p priv = (priv_p)dev->si_drv1;
668
669 switch (kn->kn_filter) {
670 case EVFILT_READ:
671 kn->kn_fop = &ngd_read_filterops;
672 kn->kn_hook = priv;
673 knlist_add(&priv->rsel.si_note, kn, 0);
674 return (0);
675 case EVFILT_WRITE:
676 kn->kn_fop = &ngd_write_filterops;
677 kn->kn_hook = priv;
678 knlist_add(&priv->wsel.si_note, kn, 0);
679 return (0);
680 default:
681 return (EINVAL);
682 }
683 }
684