110d7ccabSJulian Elischer /*- 210d7ccabSJulian Elischer * ng_etf.c Ethertype filter 310d7ccabSJulian Elischer * 410d7ccabSJulian Elischer * Copyright (c) 2001, FreeBSD Incorporated 510d7ccabSJulian Elischer * All rights reserved. 610d7ccabSJulian Elischer * 710d7ccabSJulian Elischer * Redistribution and use in source and binary forms, with or without 810d7ccabSJulian Elischer * modification, are permitted provided that the following conditions 910d7ccabSJulian Elischer * are met: 1010d7ccabSJulian Elischer * 1. Redistributions of source code must retain the above copyright 1110d7ccabSJulian Elischer * notice unmodified, this list of conditions, and the following 1210d7ccabSJulian Elischer * disclaimer. 1310d7ccabSJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1410d7ccabSJulian Elischer * notice, this list of conditions and the following disclaimer in the 1510d7ccabSJulian Elischer * documentation and/or other materials provided with the distribution. 1610d7ccabSJulian Elischer * 1710d7ccabSJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1810d7ccabSJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1910d7ccabSJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2010d7ccabSJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2110d7ccabSJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2210d7ccabSJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2310d7ccabSJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2410d7ccabSJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2510d7ccabSJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2610d7ccabSJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2710d7ccabSJulian Elischer * SUCH DAMAGE. 2810d7ccabSJulian Elischer * 2910d7ccabSJulian Elischer * Author: Julian Elischer <julian@freebsd.org> 3010d7ccabSJulian Elischer * 3110d7ccabSJulian Elischer * $FreeBSD$ 3210d7ccabSJulian Elischer */ 3310d7ccabSJulian Elischer 3410d7ccabSJulian Elischer #include <sys/param.h> 3510d7ccabSJulian Elischer #include <sys/systm.h> 3610d7ccabSJulian Elischer #include <sys/kernel.h> 3710d7ccabSJulian Elischer #include <sys/mbuf.h> 3810d7ccabSJulian Elischer #include <sys/malloc.h> 3910d7ccabSJulian Elischer #include <sys/ctype.h> 4010d7ccabSJulian Elischer #include <sys/errno.h> 4110d7ccabSJulian Elischer #include <sys/queue.h> 4210d7ccabSJulian Elischer #include <sys/syslog.h> 4310d7ccabSJulian Elischer 4410d7ccabSJulian Elischer #include <net/ethernet.h> 4510d7ccabSJulian Elischer 4610d7ccabSJulian Elischer #include <netgraph/ng_message.h> 4710d7ccabSJulian Elischer #include <netgraph/ng_parse.h> 4810d7ccabSJulian Elischer #include <netgraph/ng_etf.h> 4910d7ccabSJulian Elischer #include <netgraph/netgraph.h> 5010d7ccabSJulian Elischer 5110d7ccabSJulian Elischer /* If you do complicated mallocs you may want to do this */ 5210d7ccabSJulian Elischer /* and use it for your mallocs */ 5310d7ccabSJulian Elischer #ifdef NG_SEPARATE_MALLOC 5410d7ccabSJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ETF, "netgraph_etf", "netgraph etf node "); 5510d7ccabSJulian Elischer #else 5610d7ccabSJulian Elischer #define M_NETGRAPH_ETF M_NETGRAPH 5710d7ccabSJulian Elischer #endif 5810d7ccabSJulian Elischer 5910d7ccabSJulian Elischer /* 6010d7ccabSJulian Elischer * This section contains the netgraph method declarations for the 6110d7ccabSJulian Elischer * etf node. These methods define the netgraph 'type'. 6210d7ccabSJulian Elischer */ 6310d7ccabSJulian Elischer 6410d7ccabSJulian Elischer static ng_constructor_t ng_etf_constructor; 6510d7ccabSJulian Elischer static ng_rcvmsg_t ng_etf_rcvmsg; 6610d7ccabSJulian Elischer static ng_shutdown_t ng_etf_shutdown; 6710d7ccabSJulian Elischer static ng_newhook_t ng_etf_newhook; 6810d7ccabSJulian Elischer static ng_connect_t ng_etf_connect; 6910d7ccabSJulian Elischer static ng_rcvdata_t ng_etf_rcvdata; /* note these are both ng_rcvdata_t */ 7010d7ccabSJulian Elischer static ng_disconnect_t ng_etf_disconnect; 7110d7ccabSJulian Elischer 7210d7ccabSJulian Elischer /* Parse type for struct ng_etfstat */ 73f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_etf_stat_type_fields[] 74f0184ff8SArchie Cobbs = NG_ETF_STATS_TYPE_INFO; 7510d7ccabSJulian Elischer static const struct ng_parse_type ng_etf_stat_type = { 7610d7ccabSJulian Elischer &ng_parse_struct_type, 77f0184ff8SArchie Cobbs &ng_etf_stat_type_fields 7810d7ccabSJulian Elischer }; 7910d7ccabSJulian Elischer /* Parse type for struct ng_setfilter */ 80f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_etf_filter_type_fields[] 81f0184ff8SArchie Cobbs = NG_ETF_FILTER_TYPE_INFO; 8210d7ccabSJulian Elischer static const struct ng_parse_type ng_etf_filter_type = { 8310d7ccabSJulian Elischer &ng_parse_struct_type, 84f0184ff8SArchie Cobbs &ng_etf_filter_type_fields 8510d7ccabSJulian Elischer }; 8610d7ccabSJulian Elischer 8710d7ccabSJulian Elischer /* List of commands and how to convert arguments to/from ASCII */ 8810d7ccabSJulian Elischer static const struct ng_cmdlist ng_etf_cmdlist[] = { 8910d7ccabSJulian Elischer { 9010d7ccabSJulian Elischer NGM_ETF_COOKIE, 9110d7ccabSJulian Elischer NGM_ETF_GET_STATUS, 9210d7ccabSJulian Elischer "getstatus", 9310d7ccabSJulian Elischer NULL, 9410d7ccabSJulian Elischer &ng_etf_stat_type, 9510d7ccabSJulian Elischer }, 9610d7ccabSJulian Elischer { 9710d7ccabSJulian Elischer NGM_ETF_COOKIE, 9810d7ccabSJulian Elischer NGM_ETF_SET_FLAG, 9910d7ccabSJulian Elischer "setflag", 10010d7ccabSJulian Elischer &ng_parse_int32_type, 10110d7ccabSJulian Elischer NULL 10210d7ccabSJulian Elischer }, 10310d7ccabSJulian Elischer { 10410d7ccabSJulian Elischer NGM_ETF_COOKIE, 10510d7ccabSJulian Elischer NGM_ETF_SET_FILTER, 10610d7ccabSJulian Elischer "setfilter", 10710d7ccabSJulian Elischer &ng_etf_filter_type, 10810d7ccabSJulian Elischer NULL 10910d7ccabSJulian Elischer }, 11010d7ccabSJulian Elischer { 0 } 11110d7ccabSJulian Elischer }; 11210d7ccabSJulian Elischer 11310d7ccabSJulian Elischer /* Netgraph node type descriptor */ 11410d7ccabSJulian Elischer static struct ng_type typestruct = { 11510d7ccabSJulian Elischer NG_ABI_VERSION, 11610d7ccabSJulian Elischer NG_ETF_NODE_TYPE, 11710d7ccabSJulian Elischer NULL, 11810d7ccabSJulian Elischer ng_etf_constructor, 11910d7ccabSJulian Elischer ng_etf_rcvmsg, 12010d7ccabSJulian Elischer ng_etf_shutdown, 12110d7ccabSJulian Elischer ng_etf_newhook, 12210d7ccabSJulian Elischer NULL, 12310d7ccabSJulian Elischer ng_etf_connect, 12410d7ccabSJulian Elischer ng_etf_rcvdata, 12510d7ccabSJulian Elischer ng_etf_disconnect, 12610d7ccabSJulian Elischer ng_etf_cmdlist 12710d7ccabSJulian Elischer }; 12810d7ccabSJulian Elischer NETGRAPH_INIT(etf, &typestruct); 12910d7ccabSJulian Elischer 13010d7ccabSJulian Elischer /* Information we store for each hook on each node */ 13110d7ccabSJulian Elischer struct ETF_hookinfo { 13210d7ccabSJulian Elischer hook_p hook; 13310d7ccabSJulian Elischer }; 13410d7ccabSJulian Elischer 13510d7ccabSJulian Elischer struct filter { 13610d7ccabSJulian Elischer LIST_ENTRY(filter) next; 13710d7ccabSJulian Elischer u_int16_t ethertype; /* network order ethertype */ 13810d7ccabSJulian Elischer hook_p match_hook; /* Hook to use on a match */ 13910d7ccabSJulian Elischer }; 14010d7ccabSJulian Elischer 14110d7ccabSJulian Elischer #define HASHSIZE 16 /* Dont change this without changing HASH() */ 14210d7ccabSJulian Elischer #define HASH(et) ((((et)>>12)+((et)>>8)+((et)>>4)+(et)) & 0x0f) 14310d7ccabSJulian Elischer LIST_HEAD(filterhead, filter); 14410d7ccabSJulian Elischer 14510d7ccabSJulian Elischer /* Information we store for each node */ 14610d7ccabSJulian Elischer struct ETF { 14710d7ccabSJulian Elischer struct ETF_hookinfo downstream_hook; 14810d7ccabSJulian Elischer struct ETF_hookinfo nomatch_hook; 14910d7ccabSJulian Elischer node_p node; /* back pointer to node */ 15010d7ccabSJulian Elischer u_int packets_in; /* packets in from downstream */ 15110d7ccabSJulian Elischer u_int packets_out; /* packets out towards downstream */ 15210d7ccabSJulian Elischer u_int32_t flags; 15310d7ccabSJulian Elischer struct filterhead hashtable[HASHSIZE]; 15410d7ccabSJulian Elischer }; 15510d7ccabSJulian Elischer typedef struct ETF *etf_p; 15610d7ccabSJulian Elischer 15710d7ccabSJulian Elischer static struct filter * 15810d7ccabSJulian Elischer ng_etf_findentry(etf_p etfp, u_int16_t ethertype) 15910d7ccabSJulian Elischer { 16010d7ccabSJulian Elischer struct filterhead *chain = etfp->hashtable + HASH(ethertype); 16110d7ccabSJulian Elischer struct filter *fil; 16210d7ccabSJulian Elischer 16310d7ccabSJulian Elischer 16410d7ccabSJulian Elischer LIST_FOREACH(fil, chain, next) { 16510d7ccabSJulian Elischer if (fil->ethertype == ethertype) { 16610d7ccabSJulian Elischer return (fil); 16710d7ccabSJulian Elischer } 16810d7ccabSJulian Elischer } 16910d7ccabSJulian Elischer return (NULL); 17010d7ccabSJulian Elischer } 17110d7ccabSJulian Elischer 17210d7ccabSJulian Elischer 17310d7ccabSJulian Elischer /* 17410d7ccabSJulian Elischer * Allocate the private data structure. The generic node has already 17510d7ccabSJulian Elischer * been created. Link them together. We arrive with a reference to the node 17610d7ccabSJulian Elischer * i.e. the reference count is incremented for us already. 17710d7ccabSJulian Elischer */ 17810d7ccabSJulian Elischer static int 17910d7ccabSJulian Elischer ng_etf_constructor(node_p node) 18010d7ccabSJulian Elischer { 18110d7ccabSJulian Elischer etf_p privdata; 18210d7ccabSJulian Elischer int i; 18310d7ccabSJulian Elischer 18410d7ccabSJulian Elischer /* Initialize private descriptor */ 18510d7ccabSJulian Elischer MALLOC(privdata, etf_p, sizeof(*privdata), M_NETGRAPH_ETF, 18610d7ccabSJulian Elischer M_NOWAIT | M_ZERO); 18710d7ccabSJulian Elischer if (privdata == NULL) 18810d7ccabSJulian Elischer return (ENOMEM); 18910d7ccabSJulian Elischer for (i = 0; i < HASHSIZE; i++) { 19010d7ccabSJulian Elischer LIST_INIT((privdata->hashtable + i)); 19110d7ccabSJulian Elischer } 19210d7ccabSJulian Elischer 19310d7ccabSJulian Elischer /* Link structs together; this counts as our one reference to node */ 19410d7ccabSJulian Elischer NG_NODE_SET_PRIVATE(node, privdata); 19510d7ccabSJulian Elischer privdata->node = node; 19610d7ccabSJulian Elischer return (0); 19710d7ccabSJulian Elischer } 19810d7ccabSJulian Elischer 19910d7ccabSJulian Elischer /* 20010d7ccabSJulian Elischer * Give our ok for a hook to be added... 20110d7ccabSJulian Elischer * All names are ok. Two names are special. 20210d7ccabSJulian Elischer */ 20310d7ccabSJulian Elischer static int 20410d7ccabSJulian Elischer ng_etf_newhook(node_p node, hook_p hook, const char *name) 20510d7ccabSJulian Elischer { 20610d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(node); 20710d7ccabSJulian Elischer struct ETF_hookinfo *hpriv; 20810d7ccabSJulian Elischer 20910d7ccabSJulian Elischer if (strcmp(name, NG_ETF_HOOK_DOWNSTREAM) == 0) { 21010d7ccabSJulian Elischer etfp->downstream_hook.hook = hook; 21110d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, &etfp->downstream_hook); 21210d7ccabSJulian Elischer etfp->packets_in = 0; 21310d7ccabSJulian Elischer etfp->packets_out = 0; 21410d7ccabSJulian Elischer } else if (strcmp(name, NG_ETF_HOOK_NOMATCH) == 0) { 21510d7ccabSJulian Elischer etfp->nomatch_hook.hook = hook; 21610d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, &etfp->nomatch_hook); 21710d7ccabSJulian Elischer } else { 21810d7ccabSJulian Elischer /* 21910d7ccabSJulian Elischer * Any other hook name is valid and can 22010d7ccabSJulian Elischer * later be associated with a filter rule. 22110d7ccabSJulian Elischer */ 22210d7ccabSJulian Elischer MALLOC(hpriv, struct ETF_hookinfo *, sizeof(*hpriv), 22310d7ccabSJulian Elischer M_NETGRAPH_ETF, M_NOWAIT | M_ZERO); 22410d7ccabSJulian Elischer if (hpriv == NULL) { 22510d7ccabSJulian Elischer return (ENOMEM); 22610d7ccabSJulian Elischer } 22710d7ccabSJulian Elischer 22810d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, hpriv); 22910d7ccabSJulian Elischer hpriv->hook = hook; 23010d7ccabSJulian Elischer } 23110d7ccabSJulian Elischer return(0); 23210d7ccabSJulian Elischer } 23310d7ccabSJulian Elischer 23410d7ccabSJulian Elischer /* 23510d7ccabSJulian Elischer * Get a netgraph control message. 23610d7ccabSJulian Elischer * We actually recieve a queue item that has a pointer to the message. 23710d7ccabSJulian Elischer * If we free the item, the message will be freed too, unless we remove 23810d7ccabSJulian Elischer * it from the item using NGI_GET_MSG(); 23910d7ccabSJulian Elischer * The return address is also stored in the item, as an ng_ID_t, 24010d7ccabSJulian Elischer * accessible as NGI_RETADDR(item); 24110d7ccabSJulian Elischer * Check it is one we understand. If needed, send a response. 24210d7ccabSJulian Elischer * We could save the address for an async action later, but don't here. 24310d7ccabSJulian Elischer * Always free the message. 24410d7ccabSJulian Elischer * The response should be in a malloc'd region that the caller can 'free'. 24510d7ccabSJulian Elischer * The NG_MKRESPONSE macro does all this for us. 24610d7ccabSJulian Elischer * A response is not required. 24710d7ccabSJulian Elischer * Theoretically you could respond defferently to old message types if 24810d7ccabSJulian Elischer * the cookie in the header didn't match what we consider to be current 24910d7ccabSJulian Elischer * (so that old userland programs could continue to work). 25010d7ccabSJulian Elischer */ 25110d7ccabSJulian Elischer static int 25210d7ccabSJulian Elischer ng_etf_rcvmsg(node_p node, item_p item, hook_p lasthook) 25310d7ccabSJulian Elischer { 25410d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(node); 25510d7ccabSJulian Elischer struct ng_mesg *resp = NULL; 25610d7ccabSJulian Elischer int error = 0; 25710d7ccabSJulian Elischer struct ng_mesg *msg; 25810d7ccabSJulian Elischer 25910d7ccabSJulian Elischer NGI_GET_MSG(item, msg); 26010d7ccabSJulian Elischer /* Deal with message according to cookie and command */ 26110d7ccabSJulian Elischer switch (msg->header.typecookie) { 26210d7ccabSJulian Elischer case NGM_ETF_COOKIE: 26310d7ccabSJulian Elischer switch (msg->header.cmd) { 26410d7ccabSJulian Elischer case NGM_ETF_GET_STATUS: 26510d7ccabSJulian Elischer { 26610d7ccabSJulian Elischer struct ng_etfstat *stats; 26710d7ccabSJulian Elischer 26810d7ccabSJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); 26910d7ccabSJulian Elischer if (!resp) { 27010d7ccabSJulian Elischer error = ENOMEM; 27110d7ccabSJulian Elischer break; 27210d7ccabSJulian Elischer } 27310d7ccabSJulian Elischer stats = (struct ng_etfstat *) resp->data; 27410d7ccabSJulian Elischer stats->packets_in = etfp->packets_in; 27510d7ccabSJulian Elischer stats->packets_out = etfp->packets_out; 27610d7ccabSJulian Elischer break; 27710d7ccabSJulian Elischer } 27810d7ccabSJulian Elischer case NGM_ETF_SET_FLAG: 27910d7ccabSJulian Elischer if (msg->header.arglen != sizeof(u_int32_t)) { 28010d7ccabSJulian Elischer error = EINVAL; 28110d7ccabSJulian Elischer break; 28210d7ccabSJulian Elischer } 28310d7ccabSJulian Elischer etfp->flags = *((u_int32_t *) msg->data); 28410d7ccabSJulian Elischer break; 28510d7ccabSJulian Elischer case NGM_ETF_SET_FILTER: 28610d7ccabSJulian Elischer { 28710d7ccabSJulian Elischer struct ng_etffilter *f; 28810d7ccabSJulian Elischer struct filter *fil; 28910d7ccabSJulian Elischer hook_p hook; 29010d7ccabSJulian Elischer 29110d7ccabSJulian Elischer /* Check message long enough for this command */ 29210d7ccabSJulian Elischer if (msg->header.arglen != sizeof(*f)) { 29310d7ccabSJulian Elischer error = EINVAL; 29410d7ccabSJulian Elischer break; 29510d7ccabSJulian Elischer } 29610d7ccabSJulian Elischer 29710d7ccabSJulian Elischer /* Make sure hook referenced exists */ 29810d7ccabSJulian Elischer f = (struct ng_etffilter *)msg->data; 29910d7ccabSJulian Elischer hook = ng_findhook(node, f->matchhook); 30010d7ccabSJulian Elischer if (hook == NULL) { 30110d7ccabSJulian Elischer error = ENOENT; 30210d7ccabSJulian Elischer break; 30310d7ccabSJulian Elischer } 30410d7ccabSJulian Elischer 30510d7ccabSJulian Elischer /* and is not the downstream hook */ 30610d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 30710d7ccabSJulian Elischer error = EINVAL; 30810d7ccabSJulian Elischer break; 30910d7ccabSJulian Elischer } 31010d7ccabSJulian Elischer 31110d7ccabSJulian Elischer /* Check we don't already trap this ethertype */ 31210d7ccabSJulian Elischer if (ng_etf_findentry(etfp, 31310d7ccabSJulian Elischer htons(f->ethertype))) { 31410d7ccabSJulian Elischer error = EEXIST; 31510d7ccabSJulian Elischer break; 31610d7ccabSJulian Elischer } 31710d7ccabSJulian Elischer 31810d7ccabSJulian Elischer /* 31910d7ccabSJulian Elischer * Ok, make the filter and put it in the 32010d7ccabSJulian Elischer * hashtable ready for matching. 32110d7ccabSJulian Elischer */ 32210d7ccabSJulian Elischer MALLOC(fil, struct filter *, sizeof(*fil), 32310d7ccabSJulian Elischer M_NETGRAPH_ETF, M_NOWAIT | M_ZERO); 32410d7ccabSJulian Elischer if (fil == NULL) { 325cdea8b85SRuslan Ermilov error = ENOMEM; 326cdea8b85SRuslan Ermilov break; 32710d7ccabSJulian Elischer } 32810d7ccabSJulian Elischer 32910d7ccabSJulian Elischer fil->match_hook = hook; 33010d7ccabSJulian Elischer fil->ethertype = htons(f->ethertype); 33110d7ccabSJulian Elischer LIST_INSERT_HEAD( etfp->hashtable 33210d7ccabSJulian Elischer + HASH(fil->ethertype), 33310d7ccabSJulian Elischer fil, next); 33410d7ccabSJulian Elischer } 33510d7ccabSJulian Elischer break; 33610d7ccabSJulian Elischer default: 33710d7ccabSJulian Elischer error = EINVAL; /* unknown command */ 33810d7ccabSJulian Elischer break; 33910d7ccabSJulian Elischer } 34010d7ccabSJulian Elischer break; 34110d7ccabSJulian Elischer default: 34210d7ccabSJulian Elischer error = EINVAL; /* unknown cookie type */ 34310d7ccabSJulian Elischer break; 34410d7ccabSJulian Elischer } 34510d7ccabSJulian Elischer 34610d7ccabSJulian Elischer /* Take care of synchronous response, if any */ 34710d7ccabSJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 34810d7ccabSJulian Elischer /* Free the message and return */ 34910d7ccabSJulian Elischer NG_FREE_MSG(msg); 35010d7ccabSJulian Elischer return(error); 35110d7ccabSJulian Elischer } 35210d7ccabSJulian Elischer 35310d7ccabSJulian Elischer /* 35410d7ccabSJulian Elischer * Receive data, and do something with it. 35510d7ccabSJulian Elischer * Actually we receive a queue item which holds the data. 35610d7ccabSJulian Elischer * If we free the item it wil also froo the data and metadata unless 35710d7ccabSJulian Elischer * we have previously disassociated them using the NGI_GET_etf() macros. 35810d7ccabSJulian Elischer * Possibly send it out on another link after processing. 35910d7ccabSJulian Elischer * Possibly do something different if it comes from different 36010d7ccabSJulian Elischer * hooks. the caller will never free m or meta, so 36110d7ccabSJulian Elischer * if we use up this data or abort we must free BOTH of these. 36210d7ccabSJulian Elischer * 36310d7ccabSJulian Elischer * If we want, we may decide to force this data to be queued and reprocessed 36410d7ccabSJulian Elischer * at the netgraph NETISR time. 36510d7ccabSJulian Elischer * We would do that by setting the HK_QUEUE flag on our hook. We would do that 36610d7ccabSJulian Elischer * in the connect() method. 36710d7ccabSJulian Elischer */ 36810d7ccabSJulian Elischer static int 36910d7ccabSJulian Elischer ng_etf_rcvdata(hook_p hook, item_p item ) 37010d7ccabSJulian Elischer { 37110d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 37210d7ccabSJulian Elischer struct ether_header *eh; 37310d7ccabSJulian Elischer int error = 0; 37410d7ccabSJulian Elischer struct mbuf *m; 37510d7ccabSJulian Elischer u_int16_t ethertype; 37610d7ccabSJulian Elischer struct filter *fil; 37710d7ccabSJulian Elischer 37810d7ccabSJulian Elischer if (NG_HOOK_PRIVATE(hook) == NULL) { /* Shouldn't happen but.. */ 37910d7ccabSJulian Elischer NG_FREE_ITEM(item); 38010d7ccabSJulian Elischer } 38110d7ccabSJulian Elischer 38210d7ccabSJulian Elischer /* 38310d7ccabSJulian Elischer * Everything not from the downstream hook goes to the 38410d7ccabSJulian Elischer * downstream hook. But only if it matches the ethertype 38510d7ccabSJulian Elischer * of the source hook. Un matching must go to/from 'nomatch'. 38610d7ccabSJulian Elischer */ 38710d7ccabSJulian Elischer 38810d7ccabSJulian Elischer /* Make sure we have an entire header */ 38910d7ccabSJulian Elischer NGI_GET_M(item, m); 39010d7ccabSJulian Elischer if (m->m_len < sizeof(*eh) ) { 39110d7ccabSJulian Elischer m = m_pullup(m, sizeof(*eh)); 39210d7ccabSJulian Elischer if (m == NULL) { 39310d7ccabSJulian Elischer NG_FREE_ITEM(item); 39410d7ccabSJulian Elischer return(EINVAL); 39510d7ccabSJulian Elischer } 39610d7ccabSJulian Elischer } 39710d7ccabSJulian Elischer 39810d7ccabSJulian Elischer eh = mtod(m, struct ether_header *); 39910d7ccabSJulian Elischer ethertype = eh->ether_type; 40010d7ccabSJulian Elischer fil = ng_etf_findentry(etfp, ethertype); 40110d7ccabSJulian Elischer 40210d7ccabSJulian Elischer /* 40310d7ccabSJulian Elischer * if from downstream, select between a match hook or 40410d7ccabSJulian Elischer * the nomatch hook 40510d7ccabSJulian Elischer */ 40610d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 40710d7ccabSJulian Elischer etfp->packets_in++; 40810d7ccabSJulian Elischer if (fil && fil->match_hook) { 40910d7ccabSJulian Elischer NG_FWD_NEW_DATA(error, item, fil->match_hook, m); 41010d7ccabSJulian Elischer } else { 41110d7ccabSJulian Elischer NG_FWD_NEW_DATA(error, item,etfp->nomatch_hook.hook, m); 41210d7ccabSJulian Elischer } 41310d7ccabSJulian Elischer } else { 41410d7ccabSJulian Elischer /* 41510d7ccabSJulian Elischer * It must be heading towards the downstream. 41610d7ccabSJulian Elischer * Check that it's ethertype matches 41710d7ccabSJulian Elischer * the filters for it's input hook. 41810d7ccabSJulian Elischer * If it doesn't have one, check it's from nomatch. 41910d7ccabSJulian Elischer */ 42010d7ccabSJulian Elischer if ((fil && (fil->match_hook != hook)) 42110d7ccabSJulian Elischer || ((fil == NULL) && (hook != etfp->nomatch_hook.hook))) { 42210d7ccabSJulian Elischer NG_FREE_ITEM(item); 42310d7ccabSJulian Elischer NG_FREE_M(m); 42410d7ccabSJulian Elischer return (EPROTOTYPE); 42510d7ccabSJulian Elischer } 42610d7ccabSJulian Elischer NG_FWD_NEW_DATA( error, item, etfp->downstream_hook.hook, m); 42710d7ccabSJulian Elischer if (error == 0) { 42810d7ccabSJulian Elischer etfp->packets_out++; 42910d7ccabSJulian Elischer } 43010d7ccabSJulian Elischer } 43110d7ccabSJulian Elischer return (error); 43210d7ccabSJulian Elischer } 43310d7ccabSJulian Elischer 43410d7ccabSJulian Elischer /* 43510d7ccabSJulian Elischer * Do local shutdown processing.. 43610d7ccabSJulian Elischer * All our links and the name have already been removed. 43710d7ccabSJulian Elischer */ 43810d7ccabSJulian Elischer static int 43910d7ccabSJulian Elischer ng_etf_shutdown(node_p node) 44010d7ccabSJulian Elischer { 44110d7ccabSJulian Elischer const etf_p privdata = NG_NODE_PRIVATE(node); 44210d7ccabSJulian Elischer 44310d7ccabSJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 44410d7ccabSJulian Elischer NG_NODE_UNREF(privdata->node); 44510d7ccabSJulian Elischer FREE(privdata, M_NETGRAPH_ETF); 44610d7ccabSJulian Elischer return (0); 44710d7ccabSJulian Elischer } 44810d7ccabSJulian Elischer 44910d7ccabSJulian Elischer /* 45010d7ccabSJulian Elischer * This is called once we've already connected a new hook to the other node. 45110d7ccabSJulian Elischer * It gives us a chance to balk at the last minute. 45210d7ccabSJulian Elischer */ 45310d7ccabSJulian Elischer static int 45410d7ccabSJulian Elischer ng_etf_connect(hook_p hook) 45510d7ccabSJulian Elischer { 45610d7ccabSJulian Elischer return (0); 45710d7ccabSJulian Elischer } 45810d7ccabSJulian Elischer 45910d7ccabSJulian Elischer /* 46010d7ccabSJulian Elischer * Hook disconnection 46110d7ccabSJulian Elischer * 46210d7ccabSJulian Elischer * For this type, removal of the last link destroys the node 46310d7ccabSJulian Elischer */ 46410d7ccabSJulian Elischer static int 46510d7ccabSJulian Elischer ng_etf_disconnect(hook_p hook) 46610d7ccabSJulian Elischer { 46710d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 46810d7ccabSJulian Elischer int i; 46910d7ccabSJulian Elischer struct filter *fil; 47010d7ccabSJulian Elischer 47110d7ccabSJulian Elischer /* purge any rules that refer to this filter */ 47210d7ccabSJulian Elischer for (i = 0; i < HASHSIZE; i++) { 47310d7ccabSJulian Elischer LIST_FOREACH(fil, (etfp->hashtable + i), next) { 47410d7ccabSJulian Elischer if (fil->match_hook == hook) { 47510d7ccabSJulian Elischer LIST_REMOVE(fil, next); 476cdea8b85SRuslan Ermilov FREE(fil, M_NETGRAPH_ETF); 47710d7ccabSJulian Elischer } 47810d7ccabSJulian Elischer } 47910d7ccabSJulian Elischer } 48010d7ccabSJulian Elischer 48110d7ccabSJulian Elischer /* If it's not one of the special hooks, then free it */ 48210d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 48310d7ccabSJulian Elischer etfp->downstream_hook.hook = NULL; 48410d7ccabSJulian Elischer } else if (hook == etfp->nomatch_hook.hook) { 48510d7ccabSJulian Elischer etfp->nomatch_hook.hook = NULL; 48610d7ccabSJulian Elischer } else { 48710d7ccabSJulian Elischer if (NG_HOOK_PRIVATE(hook)) /* Paranoia */ 48810d7ccabSJulian Elischer FREE(NG_HOOK_PRIVATE(hook), M_NETGRAPH_ETF); 48910d7ccabSJulian Elischer } 49010d7ccabSJulian Elischer 49110d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, NULL); 49210d7ccabSJulian Elischer 49310d7ccabSJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 49410d7ccabSJulian Elischer && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) /* already shutting down? */ 49510d7ccabSJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook)); 49610d7ccabSJulian Elischer return (0); 49710d7ccabSJulian Elischer } 49810d7ccabSJulian Elischer 499