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