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_tag.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2006 Vadim Goncharov <vadimnuclight@tpu.ru>
    5  * All rights reserved.
    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 unmodified, this list of conditions, and the following
   12  *    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 AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * Portions Copyright (c) 1999 Whistle Communications, Inc.
   30  * (ng_bpf by Archie Cobbs <archie@freebsd.org>)
   31  *
   32  * $FreeBSD: releng/12.0/sys/netgraph/ng_tag.c 326272 2017-11-27 15:23:17Z pfg $
   33  */
   34 
   35 /*
   36  * TAG NETGRAPH NODE TYPE
   37  *
   38  * This node type accepts an arbitrary number of hooks. Each hook can be
   39  * configured for an mbuf_tags(9) definition and two hook names: a hook
   40  * for matched packets, and a hook for packets, that didn't match. Incoming
   41  * packets are examined for configured tag, matched packets are delivered
   42  * out via first hook, and not matched out via second. If corresponding hook
   43  * is not configured, packets are dropped.
   44  *
   45  * A hook can also have an outgoing tag definition configured, so that
   46  * all packets leaving the hook will be unconditionally appended with newly
   47  * allocated tag.
   48  *
   49  * Both hooks can be set to null tag definitions (that is, with zeroed
   50  * fields), so that packet tags are unmodified on output or all packets
   51  * are unconditionally forwarded to non-matching hook on input.  There is
   52  * also a possibility to replace tags by specifying strip flag on input
   53  * and replacing tag on corresponding output tag (or simply remove tag if
   54  * no tag specified on output).
   55  *
   56  * If compiled with NG_TAG_DEBUG, each hook also keeps statistics about
   57  * how many packets have matched, etc.
   58  */
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/errno.h>
   63 #include <sys/kernel.h>
   64 #include <sys/malloc.h>
   65 #include <sys/mbuf.h>
   66 #include <sys/stddef.h>
   67 
   68 #include <netgraph/ng_message.h>
   69 #include <netgraph/netgraph.h>
   70 #include <netgraph/ng_parse.h>
   71 #include <netgraph/ng_tag.h>
   72 
   73 #ifdef NG_SEPARATE_MALLOC
   74 static MALLOC_DEFINE(M_NETGRAPH_TAG, "netgraph_tag", "netgraph tag node");
   75 #else
   76 #define M_NETGRAPH_TAG M_NETGRAPH
   77 #endif
   78 
   79 #define ERROUT(x)       do { error = (x); goto done; } while (0)
   80 
   81 /*
   82  * Per hook private info.
   83  *
   84  * We've separated API and ABI here, to make easier changes in this node,
   85  * if needed. If you want to change representation, please do not break API.
   86  * We still keep API structures in memory to simplify access to them for
   87  * GET* messages, but most of data is accessed in internal representation
   88  * only.  The reason for this is to speed things up - if data will be
   89  * accessed from API structures, there would be double pointer dereferencing
   90  * in the code, which almost necessarily leads to CPU cache misses and
   91  * reloads.
   92  *
   93  * We also do another optimization by using resolved pointers to
   94  * destination hooks instead of expensive ng_findhook().
   95  */
   96 struct ng_tag_hookinfo {
   97         hook_p                  hi_match;       /* matching hook pointer */
   98         hook_p                  hi_nonmatch;    /* non-matching hook pointer */
   99         uint32_t                in_tag_cookie;
  100         uint32_t                out_tag_cookie;
  101         uint16_t                in_tag_id;
  102         uint16_t                in_tag_len;
  103         uint16_t                out_tag_id;
  104         uint16_t                out_tag_len;
  105         uint8_t                 strip;
  106         void                    *in_tag_data;
  107         void                    *out_tag_data;
  108         struct ng_tag_hookin    *in;
  109         struct ng_tag_hookout   *out;
  110 #ifdef NG_TAG_DEBUG
  111         struct ng_tag_hookstat  stats;
  112 #endif
  113 };
  114 typedef struct ng_tag_hookinfo *hinfo_p;
  115 
  116 /* Netgraph methods. */
  117 static ng_constructor_t ng_tag_constructor;
  118 static ng_rcvmsg_t      ng_tag_rcvmsg;
  119 static ng_shutdown_t    ng_tag_shutdown;
  120 static ng_newhook_t     ng_tag_newhook;
  121 static ng_rcvdata_t     ng_tag_rcvdata;
  122 static ng_disconnect_t  ng_tag_disconnect;
  123 
  124 /* Internal helper functions. */
  125 static int      ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp);
  126 static int      ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp);
  127 
  128 /* Parse types for the field 'tag_data' in structs ng_tag_hookin and out. */
  129 static int
  130 ng_tag_hookinary_getLength(const struct ng_parse_type *type,
  131         const u_char *start, const u_char *buf)
  132 {
  133         const struct ng_tag_hookin *hp;
  134 
  135         hp = (const struct ng_tag_hookin *)
  136             (buf - offsetof(struct ng_tag_hookin, tag_data));
  137         return (hp->tag_len);
  138 }
  139 
  140 static int
  141 ng_tag_hookoutary_getLength(const struct ng_parse_type *type,
  142         const u_char *start, const u_char *buf)
  143 {
  144         const struct ng_tag_hookout *hp;
  145 
  146         hp = (const struct ng_tag_hookout *)
  147             (buf - offsetof(struct ng_tag_hookout, tag_data));
  148         return (hp->tag_len);
  149 }
  150 
  151 static const struct ng_parse_type ng_tag_hookinary_type = {
  152         &ng_parse_bytearray_type,
  153         &ng_tag_hookinary_getLength
  154 };
  155 
  156 static const struct ng_parse_type ng_tag_hookoutary_type = {
  157         &ng_parse_bytearray_type,
  158         &ng_tag_hookoutary_getLength
  159 };
  160 
  161 /* Parse type for struct ng_tag_hookin. */
  162 static const struct ng_parse_struct_field ng_tag_hookin_type_fields[]
  163         = NG_TAG_HOOKIN_TYPE_INFO(&ng_tag_hookinary_type);
  164 static const struct ng_parse_type ng_tag_hookin_type = {
  165         &ng_parse_struct_type,
  166         &ng_tag_hookin_type_fields
  167 };
  168 
  169 /* Parse type for struct ng_tag_hookout. */
  170 static const struct ng_parse_struct_field ng_tag_hookout_type_fields[]
  171         = NG_TAG_HOOKOUT_TYPE_INFO(&ng_tag_hookoutary_type);
  172 static const struct ng_parse_type ng_tag_hookout_type = {
  173         &ng_parse_struct_type,
  174         &ng_tag_hookout_type_fields
  175 };
  176 
  177 #ifdef NG_TAG_DEBUG
  178 /* Parse type for struct ng_tag_hookstat. */
  179 static const struct ng_parse_struct_field ng_tag_hookstat_type_fields[]
  180         = NG_TAG_HOOKSTAT_TYPE_INFO;
  181 static const struct ng_parse_type ng_tag_hookstat_type = {
  182         &ng_parse_struct_type,
  183         &ng_tag_hookstat_type_fields
  184 };
  185 #endif
  186 
  187 /* List of commands and how to convert arguments to/from ASCII. */
  188 static const struct ng_cmdlist ng_tag_cmdlist[] = {
  189         {
  190           NGM_TAG_COOKIE,
  191           NGM_TAG_SET_HOOKIN,
  192           "sethookin",
  193           &ng_tag_hookin_type,
  194           NULL
  195         },
  196         {
  197           NGM_TAG_COOKIE,
  198           NGM_TAG_GET_HOOKIN,
  199           "gethookin",
  200           &ng_parse_hookbuf_type,
  201           &ng_tag_hookin_type
  202         },
  203         {
  204           NGM_TAG_COOKIE,
  205           NGM_TAG_SET_HOOKOUT,
  206           "sethookout",
  207           &ng_tag_hookout_type,
  208           NULL
  209         },
  210         {
  211           NGM_TAG_COOKIE,
  212           NGM_TAG_GET_HOOKOUT,
  213           "gethookout",
  214           &ng_parse_hookbuf_type,
  215           &ng_tag_hookout_type
  216         },
  217 #ifdef NG_TAG_DEBUG
  218         {
  219           NGM_TAG_COOKIE,
  220           NGM_TAG_GET_STATS,
  221           "getstats",
  222           &ng_parse_hookbuf_type,
  223           &ng_tag_hookstat_type
  224         },
  225         {
  226           NGM_TAG_COOKIE,
  227           NGM_TAG_CLR_STATS,
  228           "clrstats",
  229           &ng_parse_hookbuf_type,
  230           NULL
  231         },
  232         {
  233           NGM_TAG_COOKIE,
  234           NGM_TAG_GETCLR_STATS,
  235           "getclrstats",
  236           &ng_parse_hookbuf_type,
  237           &ng_tag_hookstat_type
  238         },
  239 #endif
  240         { 0 }
  241 };
  242 
  243 /* Netgraph type descriptor. */
  244 static struct ng_type typestruct = {
  245         .version =      NG_ABI_VERSION,
  246         .name =         NG_TAG_NODE_TYPE,
  247         .constructor =  ng_tag_constructor,
  248         .rcvmsg =       ng_tag_rcvmsg,
  249         .shutdown =     ng_tag_shutdown,
  250         .newhook =      ng_tag_newhook,
  251         .rcvdata =      ng_tag_rcvdata,
  252         .disconnect =   ng_tag_disconnect,
  253         .cmdlist =      ng_tag_cmdlist,
  254 };
  255 NETGRAPH_INIT(tag, &typestruct);
  256 
  257 /*
  258  * This are default API structures (initialized to zeroes) which are
  259  * returned in response to GET* messages when no configuration was made.
  260  * One could ask why to have this structures at all when we have
  261  * ng_tag_hookinfo initialized to zero and don't need in and out structures
  262  * at all to operate.  Unfortunatelly, we have to return thisHook field
  263  * in response to messages so the fastest and simpliest way is to have
  264  * this default structures and initialize thisHook once at hook creation
  265  * rather than to do it on every response.
  266  */
  267 
  268 /* Default tag values for a hook that matches nothing. */
  269 static const struct ng_tag_hookin ng_tag_default_in = {
  270         { '\0' },               /* to be filled in at hook creation time */
  271         { '\0' },
  272         { '\0' },
  273         0,
  274         0,
  275         0,
  276         0
  277 };
  278 
  279 /* Default tag values for a hook that adds nothing */
  280 static const struct ng_tag_hookout ng_tag_default_out = {
  281         { '\0' },               /* to be filled in at hook creation time */
  282         0,
  283         0,
  284         0
  285 };
  286 
  287 /*
  288  * Node constructor.
  289  *
  290  * We don't keep any per-node private data - we do it on per-hook basis.
  291  */
  292 static int
  293 ng_tag_constructor(node_p node)
  294 {
  295         return (0);
  296 }
  297 
  298 /*
  299  * Add a hook.
  300  */
  301 static int
  302 ng_tag_newhook(node_p node, hook_p hook, const char *name)
  303 {
  304         hinfo_p hip;
  305         int error;
  306 
  307         /* Create hook private structure. */
  308         hip = malloc(sizeof(*hip), M_NETGRAPH_TAG, M_NOWAIT | M_ZERO);
  309         if (hip == NULL)
  310                 return (ENOMEM);
  311         NG_HOOK_SET_PRIVATE(hook, hip);
  312 
  313         /*
  314          * After M_ZERO both in and out hook pointers are set to NULL,
  315          * as well as all members and pointers to in and out API
  316          * structures, so we need to set explicitly only thisHook field
  317          * in that structures (after allocating them, of course).
  318          */
  319 
  320         /* Attach the default IN data. */
  321         if ((error = ng_tag_setdata_in(hook, &ng_tag_default_in)) != 0) {
  322                 free(hip, M_NETGRAPH_TAG);
  323                 return (error);
  324         }
  325 
  326         /* Attach the default OUT data. */
  327         if ((error = ng_tag_setdata_out(hook, &ng_tag_default_out)) != 0) {
  328                 free(hip, M_NETGRAPH_TAG);
  329                 return (error);
  330         }
  331 
  332         /*
  333          * Set hook name.  This is done only once at hook creation time
  334          * since hook name can't change, rather than to do it on every
  335          * response to messages requesting API structures with data who
  336          * we are etc.
  337          */
  338         strncpy(hip->in->thisHook, name, sizeof(hip->in->thisHook) - 1);
  339         hip->in->thisHook[sizeof(hip->in->thisHook) - 1] = '\0';
  340         strncpy(hip->out->thisHook, name, sizeof(hip->out->thisHook) - 1);
  341         hip->out->thisHook[sizeof(hip->out->thisHook) - 1] = '\0';
  342         return (0);
  343 }
  344 
  345 /*
  346  * Receive a control message.
  347  */
  348 static int
  349 ng_tag_rcvmsg(node_p node, item_p item, hook_p lasthook)
  350 {
  351         struct ng_mesg *msg;
  352         struct ng_mesg *resp = NULL;
  353         int error = 0;
  354 
  355         NGI_GET_MSG(item, msg);
  356         switch (msg->header.typecookie) {
  357         case NGM_TAG_COOKIE:
  358                 switch (msg->header.cmd) {
  359                 case NGM_TAG_SET_HOOKIN:
  360                     {
  361                         struct ng_tag_hookin *const
  362                             hp = (struct ng_tag_hookin *)msg->data;
  363                         hook_p hook;
  364 
  365                         /* Sanity check. */
  366                         if (msg->header.arglen < sizeof(*hp)
  367                             || msg->header.arglen !=
  368                             NG_TAG_HOOKIN_SIZE(hp->tag_len))
  369                                 ERROUT(EINVAL);
  370 
  371                         /* Find hook. */
  372                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  373                                 ERROUT(ENOENT);
  374 
  375                         /* Set new tag values. */
  376                         if ((error = ng_tag_setdata_in(hook, hp)) != 0)
  377                                 ERROUT(error);
  378                         break;
  379                     }
  380 
  381                 case NGM_TAG_SET_HOOKOUT:
  382                     {
  383                         struct ng_tag_hookout *const
  384                             hp = (struct ng_tag_hookout *)msg->data;
  385                         hook_p hook;
  386 
  387                         /* Sanity check. */
  388                         if (msg->header.arglen < sizeof(*hp)
  389                             || msg->header.arglen !=
  390                             NG_TAG_HOOKOUT_SIZE(hp->tag_len))
  391                                 ERROUT(EINVAL);
  392 
  393                         /* Find hook. */
  394                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  395                                 ERROUT(ENOENT);
  396 
  397                         /* Set new tag values. */
  398                         if ((error = ng_tag_setdata_out(hook, hp)) != 0)
  399                                 ERROUT(error);
  400                         break;
  401                     }
  402 
  403                 case NGM_TAG_GET_HOOKIN:
  404                     {
  405                         struct ng_tag_hookin *hp;
  406                         hook_p hook;
  407 
  408                         /* Sanity check. */
  409                         if (msg->header.arglen == 0)
  410                                 ERROUT(EINVAL);
  411                         msg->data[msg->header.arglen - 1] = '\0';
  412 
  413                         /* Find hook. */
  414                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  415                                 ERROUT(ENOENT);
  416 
  417                         /* Build response. */
  418                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->in;
  419                         NG_MKRESPONSE(resp, msg,
  420                             NG_TAG_HOOKIN_SIZE(hp->tag_len), M_WAITOK);
  421                         /* M_WAITOK can't return NULL. */
  422                         bcopy(hp, resp->data,
  423                            NG_TAG_HOOKIN_SIZE(hp->tag_len));
  424                         break;
  425                     }
  426 
  427                 case NGM_TAG_GET_HOOKOUT:
  428                     {
  429                         struct ng_tag_hookout *hp;
  430                         hook_p hook;
  431 
  432                         /* Sanity check. */
  433                         if (msg->header.arglen == 0)
  434                                 ERROUT(EINVAL);
  435                         msg->data[msg->header.arglen - 1] = '\0';
  436 
  437                         /* Find hook. */
  438                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  439                                 ERROUT(ENOENT);
  440 
  441                         /* Build response. */
  442                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->out;
  443                         NG_MKRESPONSE(resp, msg,
  444                             NG_TAG_HOOKOUT_SIZE(hp->tag_len), M_WAITOK);
  445                         /* M_WAITOK can't return NULL. */
  446                         bcopy(hp, resp->data,
  447                            NG_TAG_HOOKOUT_SIZE(hp->tag_len));
  448                         break;
  449                     }
  450 
  451 #ifdef NG_TAG_DEBUG
  452                 case NGM_TAG_GET_STATS:
  453                 case NGM_TAG_CLR_STATS:
  454                 case NGM_TAG_GETCLR_STATS:
  455                     {
  456                         struct ng_tag_hookstat *stats;
  457                         hook_p hook;
  458 
  459                         /* Sanity check. */
  460                         if (msg->header.arglen == 0)
  461                                 ERROUT(EINVAL);
  462                         msg->data[msg->header.arglen - 1] = '\0';
  463 
  464                         /* Find hook. */
  465                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  466                                 ERROUT(ENOENT);
  467                         stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
  468 
  469                         /* Build response (if desired). */
  470                         if (msg->header.cmd != NGM_TAG_CLR_STATS) {
  471                                 NG_MKRESPONSE(resp,
  472                                     msg, sizeof(*stats), M_WAITOK);
  473                                 /* M_WAITOK can't return NULL. */
  474                                 bcopy(stats, resp->data, sizeof(*stats));
  475                         }
  476 
  477                         /* Clear stats (if desired). */
  478                         if (msg->header.cmd != NGM_TAG_GET_STATS)
  479                                 bzero(stats, sizeof(*stats));
  480                         break;
  481                     }
  482 #endif /* NG_TAG_DEBUG */
  483 
  484                 default:
  485                         error = EINVAL;
  486                         break;
  487                 }
  488                 break;
  489         default:
  490                 error = EINVAL;
  491                 break;
  492         }
  493 done:
  494         NG_RESPOND_MSG(error, node, item, resp);
  495         NG_FREE_MSG(msg);
  496         return (error);
  497 }
  498 
  499 /*
  500  * Receive data on a hook.
  501  *
  502  * Apply the filter, and then drop or forward packet as appropriate.
  503  */
  504 static int
  505 ng_tag_rcvdata(hook_p hook, item_p item)
  506 {
  507         struct mbuf *m;
  508         struct m_tag *tag = NULL;
  509         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  510         uint16_t type, tag_len;
  511         uint32_t cookie;
  512         hinfo_p dhip;
  513         hook_p dest;
  514         int totlen;
  515         int found = 0, error = 0;
  516 
  517         m = NGI_M(item);        /* 'item' still owns it.. we are peeking */
  518         totlen = m->m_pkthdr.len;
  519 
  520 #ifdef NG_TAG_DEBUG
  521         hip->stats.recvFrames++;
  522         hip->stats.recvOctets += totlen;
  523 #endif
  524 
  525         /* Looking up incoming tag. */
  526         cookie = hip->in_tag_cookie;
  527         type = hip->in_tag_id;
  528         tag_len = hip->in_tag_len;
  529 
  530         /*
  531          * We treat case of all zeroes specially (that is, cookie and
  532          * type are equal to zero), as we assume that such tag
  533          * can never occur in the wild.  So we don't waste time trying
  534          * to find such tag (for example, these are zeroes after hook
  535          * creation in default structures).
  536          */
  537         if ((cookie != 0) || (type != 0)) {
  538                 tag = m_tag_locate(m, cookie, type, NULL);
  539                 while (tag != NULL) {
  540                         if (memcmp((void *)(tag + 1),
  541                             hip->in_tag_data, tag_len) == 0) {
  542                                 found = 1;
  543                                 break;
  544                         }
  545                         tag = m_tag_locate(m, cookie, type, tag);
  546                 }
  547         }
  548         
  549         /* See if we got a match and find destination hook. */
  550         if (found) {
  551 #ifdef NG_TAG_DEBUG
  552                 hip->stats.recvMatchFrames++;
  553                 hip->stats.recvMatchOctets += totlen;
  554 #endif
  555                 if (hip->strip)
  556                         m_tag_delete(m, tag);
  557                 dest = hip->hi_match;
  558         } else
  559                 dest = hip->hi_nonmatch;
  560         if (dest == NULL) {
  561                 NG_FREE_ITEM(item);
  562                 return (0);
  563         }
  564 
  565         /* Deliver frame out destination hook. */
  566         dhip = NG_HOOK_PRIVATE(dest);
  567 
  568 #ifdef NG_TAG_DEBUG
  569         dhip->stats.xmitOctets += totlen;
  570         dhip->stats.xmitFrames++;
  571 #endif
  572         
  573         cookie = dhip->out_tag_cookie;
  574         type = dhip->out_tag_id;
  575         tag_len = dhip->out_tag_len;
  576         
  577         if ((cookie != 0) || (type != 0)) {
  578                 tag = m_tag_alloc(cookie, type, tag_len, M_NOWAIT);
  579                 /* XXX may be free the mbuf if tag allocation failed? */
  580                 if (tag != NULL) {
  581                         if (tag_len != 0) {
  582                                 /* copy tag data to its place */
  583                                 memcpy((void *)(tag + 1),
  584                                     dhip->out_tag_data, tag_len);
  585                         }
  586                         m_tag_prepend(m, tag);
  587                 }
  588         }
  589         
  590         NG_FWD_ITEM_HOOK(error, item, dest);
  591         return (error);
  592 }
  593 
  594 /*
  595  * Shutdown processing.
  596  */
  597 static int
  598 ng_tag_shutdown(node_p node)
  599 {
  600         NG_NODE_UNREF(node);
  601         return (0);
  602 }
  603 
  604 /*
  605  * Hook disconnection.
  606  *
  607  * We must check all hooks, since they may reference this one.
  608  */
  609 static int
  610 ng_tag_disconnect(hook_p hook)
  611 {
  612         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  613         node_p node = NG_HOOK_NODE(hook);
  614         hook_p hook2;
  615 
  616         KASSERT(hip != NULL, ("%s: null info", __func__));
  617 
  618         LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
  619                 hinfo_p priv = NG_HOOK_PRIVATE(hook2);
  620 
  621                 if (priv->hi_match == hook)
  622                         priv->hi_match = NULL;
  623                 if (priv->hi_nonmatch == hook)
  624                         priv->hi_nonmatch = NULL;
  625         }
  626 
  627         free(hip->in, M_NETGRAPH_TAG);
  628         free(hip->out, M_NETGRAPH_TAG);
  629         free(hip, M_NETGRAPH_TAG);
  630         NG_HOOK_SET_PRIVATE(hook, NULL);                        /* for good measure */
  631         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
  632             (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
  633                 ng_rmnode_self(NG_HOOK_NODE(hook));
  634         }
  635         return (0);
  636 }
  637 
  638 /************************************************************************
  639                         HELPER STUFF
  640  ************************************************************************/
  641 
  642 /*
  643  * Set the IN tag values associated with a hook.
  644  */
  645 static int
  646 ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp0)
  647 {
  648         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  649         struct ng_tag_hookin *hp;
  650         int size;
  651 
  652         /* Make a copy of the tag values and data. */
  653         size = NG_TAG_HOOKIN_SIZE(hp0->tag_len);
  654         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  655         /* M_WAITOK can't return NULL. */
  656         bcopy(hp0, hp, size);
  657 
  658         /* Free previous tag, if any, and assign new one. */
  659         if (hip->in != NULL)
  660                 free(hip->in, M_NETGRAPH_TAG);
  661         hip->in = hp;
  662 
  663         /*
  664          * Resolve hook names to pointers.
  665          *
  666          * As ng_findhook() is expensive operation to do it on every packet
  667          * after tag matching check, we do it here and use resolved pointers
  668          * where appropriate.
  669          *
  670          * XXX The drawback is that user can configure a hook to use
  671          * ifMatch/ifNotMatch hooks that do not yet exist and will be added
  672          * by user later, so that resolved pointers will be NULL even
  673          * if the hook already exists, causing node to drop packets and
  674          * user to report bugs.  We could do check for this situation on
  675          * every hook creation with pointers correction, but that involves
  676          * re-resolving for all pointers in all hooks, up to O(n^2) operations,
  677          * so we better document this in man page for user not to do
  678          * configuration before creating all hooks.
  679          */
  680         hip->hi_match = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifMatch);
  681         hip->hi_nonmatch = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifNotMatch);
  682 
  683         /* Fill internal values from API structures. */
  684         hip->in_tag_cookie = hip->in->tag_cookie;
  685         hip->in_tag_id = hip->in->tag_id;
  686         hip->in_tag_len = hip->in->tag_len;
  687         hip->strip = hip->in->strip;
  688         hip->in_tag_data = (void*)(hip->in->tag_data);
  689         return (0);
  690 }
  691 
  692 /*
  693  * Set the OUT tag values associated with a hook.
  694  */
  695 static int
  696 ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp0)
  697 {
  698         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  699         struct ng_tag_hookout *hp;
  700         int size;
  701 
  702         /* Make a copy of the tag values and data. */
  703         size = NG_TAG_HOOKOUT_SIZE(hp0->tag_len);
  704         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  705         /* M_WAITOK can't return NULL. */
  706         bcopy(hp0, hp, size);
  707 
  708         /* Free previous tag, if any, and assign new one. */
  709         if (hip->out != NULL)
  710                 free(hip->out, M_NETGRAPH_TAG);
  711         hip->out = hp;
  712 
  713         /* Fill internal values from API structures. */
  714         hip->out_tag_cookie = hip->out->tag_cookie;
  715         hip->out_tag_id = hip->out->tag_id;
  716         hip->out_tag_len = hip->out->tag_len;
  717         hip->out_tag_data = (void*)(hip->out->tag_data);
  718         return (0);
  719 }
  720 

Cache object: fdcbdad966f0360298587eb1dc776f4d


[ 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.