FreeBSD kernel netgraph code
ng_macfilter.c
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2002 Ericsson Research & Pekka Nikander
5 * Copyright (c) 2020 Nick Hibma <n_hibma@FreeBSD.org>
6 * All rights reserved.
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 unmodified, this list of conditions, and the following
13 * disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD$
31 */
32
33/*
34 * MACFILTER NETGRAPH NODE TYPE
35 *
36 * This node type routes packets from the ether hook to either the default hook
37 * if sender MAC address is not in the MAC table, or out over the specified
38 * hook if it is.
39 *
40 * Other node types can then be used to apply specific processing to the
41 * packets on each hook.
42 *
43 * If compiled with NG_MACFILTER_DEBUG the flow and resizing of the MAC table
44 * are logged to the console.
45 *
46 * If compiled with NG_MACFILTER_DEBUG_RECVDATA every packet handled is logged
47 * on the console.
48 */
49
50#include <sys/param.h>
51#include <sys/ctype.h>
52#include <sys/systm.h>
53
54#include <sys/lock.h>
55#include <sys/mbuf.h>
56#include <sys/mutex.h>
57
58#include <sys/kernel.h>
59#include <sys/malloc.h>
60
61#include <sys/socket.h>
62#include <net/ethernet.h>
63
64#include <netgraph/ng_message.h>
65#include <netgraph/netgraph.h>
66#include <netgraph/ng_parse.h>
67
68#include "ng_macfilter.h"
69
70#ifdef NG_SEPARATE_MALLOC
71MALLOC_DEFINE(M_NETGRAPH_MACFILTER, "netgraph_macfilter", "netgraph macfilter node ");
72#else
73#define M_NETGRAPH_MACFILTER M_NETGRAPH
74#endif
75
76#define MACTABLE_BLOCKSIZE 128 /* block size for incrementing table */
77
78#ifdef NG_MACFILTER_DEBUG
79#define MACFILTER_DEBUG(fmt, ...) printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, __VA_ARGS__)
80#else
81#define MACFILTER_DEBUG(fmt, ...)
82#endif
83#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
84#define MAC_S_ARGS(v) (v)[0], (v)[1], (v)[2], (v)[3], (v)[4], (v)[5]
85
86/*
87 * Parse type for struct ngm_macfilter_direct
88 */
89
95};
96
97/*
98 * Parse type for struct ngm_macfilter_direct_hookid.
99 */
100
106};
107
108/*
109 * Parse types for struct ngm_macfilter_get_macs.
110 */
111static int
113 const u_char *start, const u_char *buf)
114{
115 const struct ngm_macfilter_macs *const ngm_macs =
116 (const struct ngm_macfilter_macs *)(buf - OFFSETOF(struct ngm_macfilter_macs, macs));
117
118 return ngm_macs->n;
119}
125};
129};
133};
139};
140
141/*
142 * Parse types for struct ngm_macfilter_get_hooks.
143 */
144static int
146 const u_char *start, const u_char *buf)
147{
148 const struct ngm_macfilter_hooks *const ngm_hooks =
149 (const struct ngm_macfilter_hooks *)(buf - OFFSETOF(struct ngm_macfilter_hooks, hooks));
150
151 MACFILTER_DEBUG("buf %p, ngm_hooks %p, n %d", buf, ngm_hooks, ngm_hooks->n);
152
153 return ngm_hooks->n;
154}
155
161};
165};
169};
175};
176
177/*
178 * List of commands and how to convert arguments to/from ASCII
179 */
180static const struct ng_cmdlist ng_macfilter_cmdlist[] = {
181 {
184 "reset",
185 NULL,
186 NULL
187 },
188 {
191 "direct",
193 NULL
194 },
195 {
198 "directi",
200 NULL
201 },
202 {
205 "getmacs",
206 NULL,
208 },
209 {
212 "getclrmacs",
213 NULL,
215 },
216 {
219 "clrmacs",
220 NULL,
221 NULL,
222 },
223 {
226 "gethooks",
227 NULL,
229 },
230 { 0 }
231};
232
233/*
234 * Netgraph node type descriptor
235 */
242
243static struct ng_type typestruct = {
246 .constructor = ng_macfilter_constructor,
247 .rcvmsg = ng_macfilter_rcvmsg,
248 .shutdown = ng_macfilter_shutdown,
249 .newhook = ng_macfilter_newhook,
250 .rcvdata = ng_macfilter_rcvdata,
251 .disconnect = ng_macfilter_disconnect,
252 .cmdlist = ng_macfilter_cmdlist
253};
255
256/*
257 * Per MAC address info: the hook where to send to, the address
258 * Note: We use the same struct as in the netgraph message, so we can bcopy the
259 * array.
260 */
262
263/*
264 * Node info
265 */
266typedef struct {
267 hook_p mf_ether_hook; /* Ethernet hook */
268
269 hook_p *mf_upper; /* Upper hooks */
270 u_int mf_upper_cnt; /* Allocated # of upper slots */
271
272 struct mtx mtx; /* Mutex for MACs table */
273 mf_mac_p mf_macs; /* MAC info: dynamically allocated */
274 u_int mf_mac_allocated;/* Allocated # of MAC slots */
275 u_int mf_mac_used; /* Used # of MAC slots */
276} *macfilter_p;
277
278/*
279 * Resize the MAC table to accommodate at least mfp->mf_mac_used + 1 entries.
280 *
281 * Note: mtx already held
282 */
283static int
285{
286 int error = 0;
287
288 int n = mfp->mf_mac_allocated;
289 if (mfp->mf_mac_used < 2*MACTABLE_BLOCKSIZE-1) /* minimum size */
290 n = 2*MACTABLE_BLOCKSIZE-1;
291 else if (mfp->mf_mac_used + 2*MACTABLE_BLOCKSIZE < mfp->mf_mac_allocated) /* reduce size */
293 else if (mfp->mf_mac_used == mfp->mf_mac_allocated) /* increase size */
295
296 if (n != mfp->mf_mac_allocated) {
297 MACFILTER_DEBUG("used=%d allocated=%d->%d",
298 mfp->mf_mac_used, mfp->mf_mac_allocated, n);
299
300 mf_mac_p mfp_new = realloc(mfp->mf_macs,
301 sizeof(mfp->mf_macs[0])*n,
302 M_NETGRAPH, M_NOWAIT | M_ZERO);
303 if (mfp_new == NULL) {
304 error = -1;
305 } else {
306 mfp->mf_macs = mfp_new;
307 mfp->mf_mac_allocated = n;
308 }
309 }
310
311 return error;
312}
313
314/*
315 * Resets the macfilter to pass all received packets
316 * to the default hook.
317 *
318 * Note: mtx already held
319 */
320static void
322{
323 mfp->mf_mac_used = 0;
324
326}
327
328/*
329 * Resets the counts for each MAC address.
330 *
331 * Note: mtx already held
332 */
333static void
335{
336 int i;
337
338 for (i = 0; i < mfp->mf_mac_used; i++) {
339 mf_mac_p p = &mfp->mf_macs[i];
340 p->packets_in = p->packets_out = 0;
341 p->bytes_in = p->bytes_out = 0;
342 }
343}
344
345/*
346 * Count the number of matching macs routed to this hook.
347 *
348 * Note: mtx already held
349 */
350static int
352{
353 int i;
354 int cnt = 0;
355
356 for (i = 0; i < mfp->mf_mac_used; i++)
357 if (mfp->mf_macs[i].hookid == hookid)
358 cnt++;
359
360 return cnt;
361}
362
363/*
364 * Find a MAC address in the mac table.
365 *
366 * Returns 0 on failure with *ri set to index before which to insert a new
367 * element. Or returns 1 on success with *ri set to the index of the element
368 * that matches.
369 *
370 * Note: mtx already held.
371 */
372static u_int
373macfilter_find_mac(macfilter_p mfp, const u_char *ether, u_int *ri)
374{
375 mf_mac_p mf_macs = mfp->mf_macs;
376
377 u_int base = 0;
378 u_int range = mfp->mf_mac_used;
379 while (range > 0) {
380 u_int middle = base + (range >> 1); /* middle */
381 int d = bcmp(ether, mf_macs[middle].ether, ETHER_ADDR_LEN);
382 if (d == 0) { /* match */
383 *ri = middle;
384 return 1;
385 } else if (d > 0) { /* move right */
386 range -= middle - base + 1;
387 base = middle + 1;
388 } else { /* move left */
389 range = middle - base;
390 }
391 }
392
393 *ri = base;
394 return 0;
395}
396
397/*
398 * Change the upper hook for the given MAC address. If the hook id is zero (the
399 * default hook), the MAC address is removed from the table. Otherwise it is
400 * inserted to the table at a proper location, and the id of the hook is
401 * marked.
402 *
403 * Note: mtx already held.
404 */
405static int
406macfilter_mactable_change(macfilter_p mfp, u_char *ether, int hookid)
407{
408 u_int i;
409 int found = macfilter_find_mac(mfp, ether, &i);
410
411 mf_mac_p mf_macs = mfp->mf_macs;
412
413 MACFILTER_DEBUG("ether=" MAC_FMT " found=%d i=%d ether=" MAC_FMT " hookid=%d->%d used=%d allocated=%d",
414 MAC_S_ARGS(ether), found, i, MAC_S_ARGS(mf_macs[i].ether),
415 (found? mf_macs[i].hookid:NG_MACFILTER_HOOK_DEFAULT_ID), hookid,
416 mfp->mf_mac_used, mfp->mf_mac_allocated);
417
418 if (found) {
419 if (hookid == NG_MACFILTER_HOOK_DEFAULT_ID) { /* drop */
420 /* Compress table */
421 mfp->mf_mac_used--;
422 size_t len = (mfp->mf_mac_used - i) * sizeof(mf_macs[0]);
423 if (len > 0)
424 bcopy(&mf_macs[i+1], &mf_macs[i], len);
425
427 } else { /* modify */
428 mf_macs[i].hookid = hookid;
429 }
430 } else {
431 if (hookid == NG_MACFILTER_HOOK_DEFAULT_ID) { /* not found */
432 /* not present and not inserted */
433 return 0;
434 } else { /* add */
435 if (macfilter_mactable_resize(mfp) == -1) {
436 return ENOMEM;
437 } else {
438 mf_macs = mfp->mf_macs; /* reassign; might have moved during resize */
439
440 /* make room for new entry, unless appending */
441 size_t len = (mfp->mf_mac_used - i) * sizeof(mf_macs[0]);
442 if (len > 0)
443 bcopy(&mf_macs[i], &mf_macs[i+1], len);
444
445 mf_macs[i].hookid = hookid;
446 bcopy(ether, mf_macs[i].ether, ETHER_ADDR_LEN);
447
448 mfp->mf_mac_used++;
449 }
450 }
451 }
452
453 return 0;
454}
455
456static int
458{
459 int i, j;
460
461 for (i = 0, j = 0; i < mfp->mf_mac_used; i++) {
462 if (mfp->mf_macs[i].hookid != hookid) {
463 if (i != j)
464 bcopy(&mfp->mf_macs[i], &mfp->mf_macs[j], sizeof(mfp->mf_macs[0]));
465 j++;
466 }
467 }
468
469 int removed = i - j;
470 mfp->mf_mac_used = j;
472
473 return removed;
474}
475
476static int
477macfilter_find_hook(macfilter_p mfp, const char *hookname)
478{
479 int hookid;
480
481 for (hookid = 0; hookid < mfp->mf_upper_cnt; hookid++) {
482 if (mfp->mf_upper[hookid]) {
483 if (strncmp(NG_HOOK_NAME(mfp->mf_upper[hookid]),
484 hookname, NG_HOOKSIZ) == 0) {
485 return hookid;
486 }
487 }
488 }
489
490 return 0;
491}
492
493static int
495{
496 MACFILTER_DEBUG("ether=" MAC_FMT " hook=%s",
497 MAC_S_ARGS(md->ether), md->hookname);
498
499 int hookid = macfilter_find_hook(mfp, md->hookname);
500 if (hookid < 0)
501 return ENOENT;
502
503 return macfilter_mactable_change(mfp, md->ether, hookid);
504}
505
506static int
508{
509 MACFILTER_DEBUG("ether=" MAC_FMT " hookid=%d",
510 MAC_S_ARGS(mdi->ether), mdi->hookid);
511
512 if (mdi->hookid >= mfp->mf_upper_cnt)
513 return EINVAL;
514 else if (mfp->mf_upper[mdi->hookid] == NULL)
515 return EINVAL;
516
517 return macfilter_mactable_change(mfp, mdi->ether, mdi->hookid);
518}
519
520/*
521 * Packet handling
522 */
523
524/*
525 * Pass packets received from any upper hook to
526 * a lower hook
527 */
528static int
529macfilter_ether_output(hook_p hook, macfilter_p mfp, struct mbuf *m, hook_p *next_hook)
530{
531 struct ether_header *ether_header = mtod(m, struct ether_header *);
532 u_char *ether = ether_header->ether_dhost;
533
534 *next_hook = mfp->mf_ether_hook;
535
536 mtx_lock(&mfp->mtx);
537
538 u_int i;
539 int found = macfilter_find_mac(mfp, ether, &i);
540 if (found) {
541 mf_mac_p mf_macs = mfp->mf_macs;
542
543 mf_macs[i].packets_out++;
544 if (m->m_len > ETHER_HDR_LEN)
545 mf_macs[i].bytes_out += m->m_len - ETHER_HDR_LEN;
546
547#ifdef NG_MACFILTER_DEBUG_RECVDATA
548 MACFILTER_DEBUG("ether=" MAC_FMT " len=%db->%lldb: bytes: %s -> %s",
549 MAC_S_ARGS(ether), m->m_len - ETHER_HDR_LEN, mf_macs[i].bytes_out,
550 NG_HOOK_NAME(hook), NG_HOOK_NAME(*next_hook));
551#endif
552 } else {
553#ifdef NG_MACFILTER_DEBUG_RECVDATA
554 MACFILTER_DEBUG("ether=" MAC_FMT " len=%db->?b: bytes: %s->%s",
555 MAC_S_ARGS(ether), m->m_len - ETHER_HDR_LEN,
556 NG_HOOK_NAME(hook), NG_HOOK_NAME(*next_hook));
557#endif
558 }
559
560 mtx_unlock(&mfp->mtx);
561
562 return 0;
563}
564
565/*
566 * Search for the right upper hook, based on the source ethernet
567 * address. If not found, pass to the default upper hook.
568 */
569static int
570macfilter_ether_input(hook_p hook, macfilter_p mfp, struct mbuf *m, hook_p *next_hook)
571{
572 struct ether_header *ether_header = mtod(m, struct ether_header *);
573 u_char *ether = ether_header->ether_shost;
574 int hookid = NG_MACFILTER_HOOK_DEFAULT_ID;
575
576 mtx_lock(&mfp->mtx);
577
578 u_int i;
579 int found = macfilter_find_mac(mfp, ether, &i);
580 if (found) {
581 mf_mac_p mf_macs = mfp->mf_macs;
582
583 mf_macs[i].packets_in++;
584 if (m->m_len > ETHER_HDR_LEN)
585 mf_macs[i].bytes_in += m->m_len - ETHER_HDR_LEN;
586
587 hookid = mf_macs[i].hookid;
588
589#ifdef NG_MACFILTER_DEBUG_RECVDATA
590 MACFILTER_DEBUG("ether=" MAC_FMT " len=%db->%lldb: bytes: %s->%s",
591 MAC_S_ARGS(ether), m->m_len - ETHER_HDR_LEN, mf_macs[i].bytes_in,
592 NG_HOOK_NAME(hook), NG_HOOK_NAME(*next_hook));
593#endif
594 } else {
595#ifdef NG_MACFILTER_DEBUG_RECVDATA
596 MACFILTER_DEBUG("ether=" MAC_FMT " len=%db->?b: bytes: %s->%s",
597 MAC_S_ARGS(ether), m->m_len - ETHER_HDR_LEN,
598 NG_HOOK_NAME(hook), NG_HOOK_NAME(*next_hook));
599#endif
600 }
601
602 if (hookid >= mfp->mf_upper_cnt)
603 *next_hook = NULL;
604 else
605 *next_hook = mfp->mf_upper[hookid];
606
607 mtx_unlock(&mfp->mtx);
608
609 return 0;
610}
611
612/*
613 * ======================================================================
614 * Netgraph hooks
615 * ======================================================================
616 */
617
618/*
619 * See basic netgraph code for comments on the individual functions.
620 */
621
622static int
624{
625 macfilter_p mfp = malloc(sizeof(*mfp), M_NETGRAPH, M_NOWAIT | M_ZERO);
626 if (mfp == NULL)
627 return ENOMEM;
628
629 int error = macfilter_mactable_resize(mfp);
630 if (error)
631 return error;
632
633 NG_NODE_SET_PRIVATE(node, mfp);
634
635 mtx_init(&mfp->mtx, "Macfilter table", NULL, MTX_DEF);
636
637 return (0);
638}
639
640static int
641ng_macfilter_newhook(node_p node, hook_p hook, const char *hookname)
642{
643 const macfilter_p mfp = NG_NODE_PRIVATE(node);
644
645 MACFILTER_DEBUG("%s", hookname);
646
647 if (strcmp(hookname, NG_MACFILTER_HOOK_ETHER) == 0) {
648 mfp->mf_ether_hook = hook;
649 } else {
650 int hookid;
651 if (strcmp(hookname, NG_MACFILTER_HOOK_DEFAULT) == 0) {
653 } else {
654 for (hookid = 1; hookid < mfp->mf_upper_cnt; hookid++)
655 if (mfp->mf_upper[hookid] == NULL)
656 break;
657 }
658
659 if (hookid >= mfp->mf_upper_cnt) {
660 MACFILTER_DEBUG("upper cnt %d -> %d", mfp->mf_upper_cnt, hookid + 1);
661
662 mfp->mf_upper_cnt = hookid + 1;
663 mfp->mf_upper = realloc(mfp->mf_upper,
664 sizeof(mfp->mf_upper[0])*mfp->mf_upper_cnt,
665 M_NETGRAPH, M_NOWAIT | M_ZERO);
666 }
667
668 mfp->mf_upper[hookid] = hook;
669 }
670
671 return(0);
672}
673
674static int
676{
677 const macfilter_p mfp = NG_NODE_PRIVATE(node);
678 struct ng_mesg *resp = NULL;
679 struct ng_mesg *msg;
680 int error = 0;
681 struct ngm_macfilter_macs *ngm_macs;
682 struct ngm_macfilter_hooks *ngm_hooks;
683 struct ngm_macfilter_direct *md;
684 struct ngm_macfilter_direct_hookid *mdi;
685 int n = 0, i = 0;
686 int hookid = 0;
687 int resplen;
688
689 NGI_GET_MSG(item, msg);
690
691 mtx_lock(&mfp->mtx);
692
693 switch (msg->header.typecookie) {
695 switch (msg->header.cmd) {
696
698 macfilter_reset(mfp);
699 break;
700
702 if (msg->header.arglen != sizeof(struct ngm_macfilter_direct)) {
703 MACFILTER_DEBUG("direct: wrong type length (%d, expected %zu)",
704 msg->header.arglen, sizeof(struct ngm_macfilter_direct));
705 error = EINVAL;
706 break;
707 }
708 md = (struct ngm_macfilter_direct *)msg->data;
709 error = macfilter_direct(mfp, md);
710 break;
712 if (msg->header.arglen != sizeof(struct ngm_macfilter_direct_hookid)) {
713 MACFILTER_DEBUG("direct hookid: wrong type length (%d, expected %zu)",
714 msg->header.arglen, sizeof(struct ngm_macfilter_direct));
715 error = EINVAL;
716 break;
717 }
718 mdi = (struct ngm_macfilter_direct_hookid *)msg->data;
719 error = macfilter_direct_hookid(mfp, mdi);
720 break;
721
724 n = mfp->mf_mac_used;
725 resplen = sizeof(struct ngm_macfilter_macs) + n * sizeof(struct ngm_macfilter_mac);
726 NG_MKRESPONSE(resp, msg, resplen, M_NOWAIT);
727 if (resp == NULL) {
728 error = ENOMEM;
729 break;
730 }
731 ngm_macs = (struct ngm_macfilter_macs *)resp->data;
732 ngm_macs->n = n;
733 bcopy(mfp->mf_macs, &ngm_macs->macs[0], n * sizeof(struct ngm_macfilter_mac));
734
737 break;
738
741 break;
742
744 for (hookid = 0; hookid < mfp->mf_upper_cnt; hookid++)
745 if (mfp->mf_upper[hookid] != NULL)
746 n++;
747 resplen = sizeof(struct ngm_macfilter_hooks) + n * sizeof(struct ngm_macfilter_hook);
748 NG_MKRESPONSE(resp, msg, resplen, M_NOWAIT | M_ZERO);
749 if (resp == NULL) {
750 error = ENOMEM;
751 break;
752 }
753
754 ngm_hooks = (struct ngm_macfilter_hooks *)resp->data;
755 ngm_hooks->n = n;
756 for (hookid = 0; hookid < mfp->mf_upper_cnt; hookid++) {
757 if (mfp->mf_upper[hookid] != NULL) {
758 struct ngm_macfilter_hook *ngm_hook = &ngm_hooks->hooks[i++];
759 strlcpy(ngm_hook->hookname,
761 NG_HOOKSIZ);
762 ngm_hook->hookid = hookid;
763 ngm_hook->maccnt = macfilter_mac_count(mfp, hookid);
764 }
765 }
766 break;
767
768 default:
769 error = EINVAL; /* unknown command */
770 break;
771 }
772 break;
773
774 default:
775 error = EINVAL; /* unknown cookie type */
776 break;
777 }
778
779 mtx_unlock(&mfp->mtx);
780
781 NG_RESPOND_MSG(error, node, item, resp);
782 NG_FREE_MSG(msg);
783
784 return error;
785}
786
787static int
789{
790 const macfilter_p mfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
791 int error;
792 hook_p next_hook = NULL;
793 struct mbuf *m;
794
795 m = NGI_M(item); /* 'item' still owns it. We are peeking */
796 MACFILTER_DEBUG("%s", NG_HOOK_NAME(hook));
797
798 if (hook == mfp->mf_ether_hook)
799 error = macfilter_ether_input(hook, mfp, m, &next_hook);
800 else if (mfp->mf_ether_hook != NULL)
801 error = macfilter_ether_output(hook, mfp, m, &next_hook);
802
803 if (next_hook == NULL) {
804 NG_FREE_ITEM(item);
805 return (0);
806 }
807
808 NG_FWD_ITEM_HOOK(error, item, next_hook);
809
810 return error;
811}
812
813static int
815{
816 const macfilter_p mfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
817
818 mtx_lock(&mfp->mtx);
819
820 if (mfp->mf_ether_hook == hook) {
821 mfp->mf_ether_hook = NULL;
822
823 MACFILTER_DEBUG("%s", NG_HOOK_NAME(hook));
824 } else {
825 int hookid;
826
827 for (hookid = 0; hookid < mfp->mf_upper_cnt; hookid++) {
828 if (mfp->mf_upper[hookid] == hook) {
829 mfp->mf_upper[hookid] = NULL;
830
831#ifndef NG_MACFILTER_DEBUG
833#else
834 int cnt = macfilter_mactable_remove_by_hookid(mfp, hookid);
835
836 MACFILTER_DEBUG("%s: removed %d MACs", NG_HOOK_NAME(hook), cnt);
837#endif
838 break;
839 }
840 }
841
842 if (hookid == mfp->mf_upper_cnt - 1) {
843 /* Reduce the size of the array when the last element was removed */
844 for (--hookid; hookid >= 0 && mfp->mf_upper[hookid] == NULL; hookid--)
845 ;
846
847 MACFILTER_DEBUG("upper cnt %d -> %d", mfp->mf_upper_cnt, hookid + 1);
848 mfp->mf_upper_cnt = hookid + 1;
849 mfp->mf_upper = realloc(mfp->mf_upper,
850 sizeof(mfp->mf_upper[0])*mfp->mf_upper_cnt,
851 M_NETGRAPH, M_NOWAIT | M_ZERO);
852 }
853 }
854
855 mtx_unlock(&mfp->mtx);
856
857 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
858 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
860 }
861
862 return (0);
863}
864
865static int
867{
868 const macfilter_p mfp = NG_NODE_PRIVATE(node);
869
870 mtx_destroy(&mfp->mtx);
871 free(mfp->mf_upper, M_NETGRAPH);
872 free(mfp->mf_macs, M_NETGRAPH);
873 free(mfp, M_NETGRAPH);
874
875 NG_NODE_UNREF(node);
876
877 return (0);
878}
#define NGI_M(i)
Definition: netgraph.h:833
#define NG_HOOK_NODE(hook)
Definition: netgraph.h:339
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
Definition: netgraph.h:105
#define NG_FWD_ITEM_HOOK(error, item, hook)
Definition: netgraph.h:898
int ng_disconnect_t(hook_p hook)
Definition: netgraph.h:107
#define NG_NODE_SET_PRIVATE(node, val)
Definition: netgraph.h:608
#define NG_RESPOND_MSG(error, here, item, resp)
Definition: netgraph.h:1025
#define NG_NODE_IS_VALID(node)
Definition: netgraph.h:610
#define NG_NODE_UNREF(node)
Definition: netgraph.h:607
int ng_rmnode_self(node_p here)
Definition: ng_base.c:1609
int ng_rcvdata_t(hook_p hook, item_p item)
Definition: netgraph.h:106
int ng_shutdown_t(node_p node)
Definition: netgraph.h:101
#define NG_HOOK_NAME(hook)
Definition: netgraph.h:331
#define NG_FREE_ITEM(item)
Definition: netgraph.h:847
int ng_constructor_t(node_p node)
Definition: netgraph.h:99
#define NG_FREE_MSG(msg)
Definition: netgraph.h:938
#define NG_ABI_VERSION
Definition: netgraph.h:77
#define NG_NODE_NUMHOOKS(node)
Definition: netgraph.h:615
#define NGI_GET_MSG(i, m)
Definition: netgraph.h:858
#define NG_NODE_PRIVATE(node)
Definition: netgraph.h:609
int ng_newhook_t(node_p node, hook_p hook, const char *name)
Definition: netgraph.h:102
#define OFFSETOF(s, e)
Definition: ng_bpf.c:82
u_int8_t type
MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node")
static u_int macfilter_find_mac(macfilter_p mfp, const u_char *ether, u_int *ri)
Definition: ng_macfilter.c:373
static int macfilter_find_hook(macfilter_p mfp, const char *hookname)
Definition: ng_macfilter.c:477
static const struct ng_parse_type ng_macfilter_direct_hookid_type
Definition: ng_macfilter.c:103
static const struct ng_parse_array_info ng_macfilter_hooks_array_info
Definition: ng_macfilter.c:162
static int macfilter_mactable_remove_by_hookid(macfilter_p mfp, int hookid)
Definition: ng_macfilter.c:457
#define MACTABLE_BLOCKSIZE
Definition: ng_macfilter.c:76
static const struct ng_cmdlist ng_macfilter_cmdlist[]
Definition: ng_macfilter.c:180
static ng_disconnect_t ng_macfilter_disconnect
Definition: ng_macfilter.c:241
static int macfilter_get_upper_hook_count(const struct ng_parse_type *type, const u_char *start, const u_char *buf)
Definition: ng_macfilter.c:145
static const struct ng_parse_struct_field ng_macfilter_hook_fields[]
Definition: ng_macfilter.c:157
static const struct ng_parse_type ng_macfilter_macs_array_type
Definition: ng_macfilter.c:130
static int macfilter_ether_output(hook_p hook, macfilter_p mfp, struct mbuf *m, hook_p *next_hook)
Definition: ng_macfilter.c:529
static int macfilter_direct(macfilter_p mfp, struct ngm_macfilter_direct *md)
Definition: ng_macfilter.c:494
static ng_rcvdata_t ng_macfilter_rcvdata
Definition: ng_macfilter.c:240
static const struct ng_parse_struct_field macfilter_direct_fields[]
Definition: ng_macfilter.c:91
static const struct ng_parse_type ng_macfilter_hooks_array_type
Definition: ng_macfilter.c:166
static ng_rcvmsg_t ng_macfilter_rcvmsg
Definition: ng_macfilter.c:237
static ng_newhook_t ng_macfilter_newhook
Definition: ng_macfilter.c:239
#define MACFILTER_DEBUG(fmt,...)
Definition: ng_macfilter.c:81
static int macfilter_mac_count(macfilter_p mfp, int hookid)
Definition: ng_macfilter.c:351
struct ngm_macfilter_mac * mf_mac_p
Definition: ng_macfilter.c:261
NETGRAPH_INIT(macfilter, &typestruct)
static int macfilter_direct_hookid(macfilter_p mfp, struct ngm_macfilter_direct_hookid *mdi)
Definition: ng_macfilter.c:507
static void macfilter_reset_stats(macfilter_p mfp)
Definition: ng_macfilter.c:334
static struct ng_type typestruct
Definition: ng_macfilter.c:243
static int macfilter_ether_input(hook_p hook, macfilter_p mfp, struct mbuf *m, hook_p *next_hook)
Definition: ng_macfilter.c:570
static const struct ng_parse_struct_field ng_macfilter_macs_fields[]
Definition: ng_macfilter.c:135
static const struct ng_parse_type ng_macfilter_hooks_type
Definition: ng_macfilter.c:172
static const struct ng_parse_array_info ng_macfilter_macs_array_info
Definition: ng_macfilter.c:126
static const struct ng_parse_type ng_macfilter_hook_type
Definition: ng_macfilter.c:158
#define MAC_FMT
Definition: ng_macfilter.c:83
#define M_NETGRAPH_MACFILTER
Definition: ng_macfilter.c:73
static ng_shutdown_t ng_macfilter_shutdown
Definition: ng_macfilter.c:238
static const struct ng_parse_struct_field ng_macfilter_mac_fields[]
Definition: ng_macfilter.c:121
#define MAC_S_ARGS(v)
Definition: ng_macfilter.c:84
static const struct ng_parse_type ng_macfilter_macs_type
Definition: ng_macfilter.c:136
static const struct ng_parse_type ng_macfilter_mac_type
Definition: ng_macfilter.c:122
static void macfilter_reset(macfilter_p mfp)
Definition: ng_macfilter.c:321
static int macfilter_get_macs_count(const struct ng_parse_type *type, const u_char *start, const u_char *buf)
Definition: ng_macfilter.c:112
static ng_constructor_t ng_macfilter_constructor
Definition: ng_macfilter.c:236
static int macfilter_mactable_resize(macfilter_p mfp)
Definition: ng_macfilter.c:284
static int macfilter_mactable_change(macfilter_p mfp, u_char *ether, int hookid)
Definition: ng_macfilter.c:406
static const struct ng_parse_struct_field macfilter_direct_ndx_fields[]
Definition: ng_macfilter.c:102
static const struct ng_parse_type ng_macfilter_direct_type
Definition: ng_macfilter.c:92
static const struct ng_parse_struct_field ng_macfilter_hooks_fields[]
Definition: ng_macfilter.c:171
#define NG_MACFILTER_NODE_TYPE
Definition: ng_macfilter.h:36
#define NGM_MACFILTER_MAC_FIELDS
Definition: ng_macfilter.h:89
#define NGM_MACFILTER_HOOK_FIELDS
Definition: ng_macfilter.h:115
#define NGM_MACFILTER_DIRECT_FIELDS
Definition: ng_macfilter.h:63
#define NGM_MACFILTER_HOOKS_FIELDS
Definition: ng_macfilter.h:126
#define NG_MACFILTER_HOOK_DEFAULT
Definition: ng_macfilter.h:41
#define NG_MACFILTER_HOOK_ETHER
Definition: ng_macfilter.h:40
#define NGM_MACFILTER_MACS_FIELDS
Definition: ng_macfilter.h:103
#define NGM_MACFILTER_COOKIE
Definition: ng_macfilter.h:37
#define NGM_MACFILTER_DIRECT_NDX_FIELDS
Definition: ng_macfilter.h:74
#define NG_MACFILTER_HOOK_DEFAULT_ID
Definition: ng_macfilter.h:43
@ NGM_MACFILTER_DIRECT
Definition: ng_macfilter.h:50
@ NGM_MACFILTER_GET_HOOKS
Definition: ng_macfilter.h:55
@ NGM_MACFILTER_GET_MACS
Definition: ng_macfilter.h:52
@ NGM_MACFILTER_DIRECT_HOOKID
Definition: ng_macfilter.h:51
@ NGM_MACFILTER_CLR_MACS
Definition: ng_macfilter.h:54
@ NGM_MACFILTER_GETCLR_MACS
Definition: ng_macfilter.h:53
@ NGM_MACFILTER_RESET
Definition: ng_macfilter.h:49
#define NG_MKRESPONSE(rsp, msg, len, how)
Definition: ng_message.h:396
#define NG_HOOKSIZ
Definition: ng_message.h:49
const struct ng_parse_type ng_parse_array_type
Definition: ng_parse.c:318
const struct ng_parse_type ng_parse_struct_type
Definition: ng_parse.c:222
struct mtx mtx
Definition: ng_macfilter.c:272
u_int mf_upper_cnt
Definition: ng_macfilter.c:270
hook_p * mf_upper
Definition: ng_macfilter.c:269
mf_mac_p mf_macs
Definition: ng_macfilter.c:273
u_int mf_mac_allocated
Definition: ng_macfilter.c:274
hook_p mf_ether_hook
Definition: ng_macfilter.c:267
u_int mf_mac_used
Definition: ng_macfilter.c:275
u_int32_t arglen
Definition: ng_message.h:62
u_int32_t typecookie
Definition: ng_message.h:66
struct ng_mesg::ng_msghdr header
char data[]
Definition: ng_message.h:69
u_int32_t version
Definition: netgraph.h:1077
u_char ether[ETHER_ADDR_LEN]
Definition: ng_macfilter.h:71
u_char ether[ETHER_ADDR_LEN]
Definition: ng_macfilter.h:60
u_char hookname[NG_HOOKSIZ]
Definition: ng_macfilter.h:61
u_char hookname[NG_HOOKSIZ]
Definition: ng_macfilter.h:111
struct ngm_macfilter_hook hooks[]
Definition: ng_macfilter.h:124
u_int64_t packets_out
Definition: ng_macfilter.h:86
u_int16_t hookid
Definition: ng_macfilter.h:83
u_int64_t bytes_in
Definition: ng_macfilter.h:85
u_int64_t packets_in
Definition: ng_macfilter.h:84
u_int64_t bytes_out
Definition: ng_macfilter.h:87
struct ngm_macfilter_mac macs[]
Definition: ng_macfilter.h:101