The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_macfilter.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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
   71 MALLOC_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 
   90 static const struct ng_parse_struct_field macfilter_direct_fields[]
   91         = NGM_MACFILTER_DIRECT_FIELDS;
   92 static const struct ng_parse_type ng_macfilter_direct_type = {
   93     &ng_parse_struct_type,
   94     &macfilter_direct_fields
   95 };
   96 
   97 /*
   98  * Parse type for struct ngm_macfilter_direct_hookid.
   99  */
  100 
  101 static const struct ng_parse_struct_field macfilter_direct_ndx_fields[]
  102         = NGM_MACFILTER_DIRECT_NDX_FIELDS;
  103 static const struct ng_parse_type ng_macfilter_direct_hookid_type = {
  104     &ng_parse_struct_type,
  105     &macfilter_direct_ndx_fields
  106 };
  107 
  108 /*
  109  * Parse types for struct ngm_macfilter_get_macs.
  110  */
  111 static int
  112 macfilter_get_macs_count(const struct ng_parse_type *type,
  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 }
  120 static const struct ng_parse_struct_field ng_macfilter_mac_fields[]
  121         = NGM_MACFILTER_MAC_FIELDS;
  122 static const struct ng_parse_type ng_macfilter_mac_type = {
  123     &ng_parse_struct_type,
  124     ng_macfilter_mac_fields,
  125 };
  126 static const struct ng_parse_array_info ng_macfilter_macs_array_info = {
  127     &ng_macfilter_mac_type,
  128     macfilter_get_macs_count
  129 };
  130 static const struct ng_parse_type ng_macfilter_macs_array_type = {
  131     &ng_parse_array_type,
  132     &ng_macfilter_macs_array_info
  133 };
  134 static const struct ng_parse_struct_field ng_macfilter_macs_fields[]
  135         = NGM_MACFILTER_MACS_FIELDS;
  136 static const struct ng_parse_type ng_macfilter_macs_type = {
  137     &ng_parse_struct_type,
  138     &ng_macfilter_macs_fields
  139 };
  140 
  141 /*
  142  * Parse types for struct ngm_macfilter_get_hooks.
  143  */
  144 static int
  145 macfilter_get_upper_hook_count(const struct ng_parse_type *type,
  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 
  156 static const struct ng_parse_struct_field ng_macfilter_hook_fields[]
  157         = NGM_MACFILTER_HOOK_FIELDS;
  158 static const struct ng_parse_type ng_macfilter_hook_type = {
  159     &ng_parse_struct_type,
  160     ng_macfilter_hook_fields,
  161 };
  162 static const struct ng_parse_array_info ng_macfilter_hooks_array_info = {
  163     &ng_macfilter_hook_type,
  164     macfilter_get_upper_hook_count   
  165 };
  166 static const struct ng_parse_type ng_macfilter_hooks_array_type = {
  167     &ng_parse_array_type,
  168     &ng_macfilter_hooks_array_info
  169 };
  170 static const struct ng_parse_struct_field ng_macfilter_hooks_fields[]
  171         = NGM_MACFILTER_HOOKS_FIELDS;
  172 static const struct ng_parse_type ng_macfilter_hooks_type = {
  173     &ng_parse_struct_type,
  174     &ng_macfilter_hooks_fields
  175 };
  176 
  177 /*
  178  * List of commands and how to convert arguments to/from ASCII 
  179  */
  180 static const struct ng_cmdlist ng_macfilter_cmdlist[] = {
  181     {
  182         NGM_MACFILTER_COOKIE,
  183         NGM_MACFILTER_RESET,
  184         "reset",
  185         NULL,
  186         NULL
  187     },
  188     {
  189         NGM_MACFILTER_COOKIE,
  190         NGM_MACFILTER_DIRECT,
  191         "direct",
  192         &ng_macfilter_direct_type,
  193         NULL
  194     },
  195     {
  196         NGM_MACFILTER_COOKIE,
  197         NGM_MACFILTER_DIRECT_HOOKID,
  198         "directi",
  199         &ng_macfilter_direct_hookid_type,
  200         NULL
  201     },
  202     {
  203         NGM_MACFILTER_COOKIE,
  204         NGM_MACFILTER_GET_MACS,
  205         "getmacs",
  206         NULL,
  207         &ng_macfilter_macs_type
  208     },
  209     {
  210         NGM_MACFILTER_COOKIE,
  211         NGM_MACFILTER_GETCLR_MACS,
  212         "getclrmacs",
  213         NULL,
  214         &ng_macfilter_macs_type
  215     },
  216     {
  217         NGM_MACFILTER_COOKIE,
  218         NGM_MACFILTER_CLR_MACS,
  219         "clrmacs",
  220         NULL,
  221         NULL,
  222     },
  223     {
  224         NGM_MACFILTER_COOKIE,
  225         NGM_MACFILTER_GET_HOOKS,
  226         "gethooks",
  227         NULL,
  228         &ng_macfilter_hooks_type
  229     },
  230     { 0 }
  231 };
  232 
  233 /*
  234  * Netgraph node type descriptor 
  235  */
  236 static ng_constructor_t ng_macfilter_constructor;
  237 static ng_rcvmsg_t      ng_macfilter_rcvmsg;
  238 static ng_shutdown_t    ng_macfilter_shutdown;
  239 static ng_newhook_t     ng_macfilter_newhook;
  240 static ng_rcvdata_t     ng_macfilter_rcvdata;
  241 static ng_disconnect_t  ng_macfilter_disconnect;
  242 
  243 static struct ng_type typestruct = {
  244     .version =     NG_ABI_VERSION,
  245     .name =        NG_MACFILTER_NODE_TYPE,
  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 };
  254 NETGRAPH_INIT(macfilter, &typestruct);
  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  */
  261 typedef struct ngm_macfilter_mac *mf_mac_p;
  262 
  263 /*
  264  * Node info
  265  */
  266 typedef 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  */
  283 static int
  284 macfilter_mactable_resize(macfilter_p mfp)
  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 */
  292         n = mfp->mf_mac_allocated - MACTABLE_BLOCKSIZE;
  293     else if (mfp->mf_mac_used == mfp->mf_mac_allocated)                         /* increase size */
  294         n = mfp->mf_mac_allocated + MACTABLE_BLOCKSIZE;
  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  */
  320 static void
  321 macfilter_reset(macfilter_p mfp)
  322 {
  323     mfp->mf_mac_used = 0;
  324 
  325     macfilter_mactable_resize(mfp);
  326 }
  327 
  328 /*
  329  * Resets the counts for each MAC address.
  330  *
  331  * Note: mtx already held
  332  */
  333 static void
  334 macfilter_reset_stats(macfilter_p mfp)
  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  */
  350 static int
  351 macfilter_mac_count(macfilter_p mfp, int hookid)
  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  */
  372 static u_int
  373 macfilter_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  */
  405 static int
  406 macfilter_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 
  426             macfilter_mactable_resize(mfp);
  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 
  456 static int
  457 macfilter_mactable_remove_by_hookid(macfilter_p mfp, int hookid)
  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;
  471     macfilter_mactable_resize(mfp);
  472 
  473     return removed;
  474 }
  475 
  476 static int
  477 macfilter_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 
  493 static int
  494 macfilter_direct(macfilter_p mfp, struct ngm_macfilter_direct *md)
  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 
  506 static int
  507 macfilter_direct_hookid(macfilter_p mfp, struct ngm_macfilter_direct_hookid *mdi)
  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  */
  528 static int
  529 macfilter_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  */
  569 static int
  570 macfilter_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 
  622 static int
  623 ng_macfilter_constructor(node_p node)
  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 
  640 static int
  641 ng_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) {
  652             hookid = NG_MACFILTER_HOOK_DEFAULT_ID;
  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 
  674 static int
  675 ng_macfilter_rcvmsg(node_p node, item_p item, hook_p lasthook)
  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) {
  694     case NGM_MACFILTER_COOKIE: 
  695         switch (msg->header.cmd) {
  696 
  697         case NGM_MACFILTER_RESET:
  698             macfilter_reset(mfp);
  699             break;
  700 
  701         case NGM_MACFILTER_DIRECT:
  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;
  711         case NGM_MACFILTER_DIRECT_HOOKID:
  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 
  722         case NGM_MACFILTER_GET_MACS:
  723         case NGM_MACFILTER_GETCLR_MACS:
  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 
  735             if (msg->header.cmd == NGM_MACFILTER_GETCLR_MACS)
  736                 macfilter_reset_stats(mfp);
  737             break;
  738 
  739         case NGM_MACFILTER_CLR_MACS:
  740             macfilter_reset_stats(mfp);
  741             break;
  742 
  743         case NGM_MACFILTER_GET_HOOKS:
  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,
  760                             NG_HOOK_NAME(mfp->mf_upper[hookid]),
  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 
  787 static int
  788 ng_macfilter_rcvdata(hook_p hook, item_p item)
  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 
  813 static int
  814 ng_macfilter_disconnect(hook_p hook)
  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
  832                 macfilter_mactable_remove_by_hookid(mfp, hookid);
  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)))) {
  859         ng_rmnode_self(NG_HOOK_NODE(hook));
  860     }
  861 
  862     return (0);
  863 }
  864 
  865 static int
  866 ng_macfilter_shutdown(node_p node)
  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 }

Cache object: da3ad18978136c336aaaac2a46648e5b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.