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 = { 115f8aae777SJulian Elischer .version = NG_ABI_VERSION, 116f8aae777SJulian Elischer .name = NG_ETF_NODE_TYPE, 117f8aae777SJulian Elischer .constructor = ng_etf_constructor, 118f8aae777SJulian Elischer .rcvmsg = ng_etf_rcvmsg, 119f8aae777SJulian Elischer .shutdown = ng_etf_shutdown, 120f8aae777SJulian Elischer .newhook = ng_etf_newhook, 121f8aae777SJulian Elischer .connect = ng_etf_connect, 122f8aae777SJulian Elischer .rcvdata = ng_etf_rcvdata, 123f8aae777SJulian Elischer .disconnect = ng_etf_disconnect, 124f8aae777SJulian Elischer .cmdlist = ng_etf_cmdlist, 12510d7ccabSJulian Elischer }; 12610d7ccabSJulian Elischer NETGRAPH_INIT(etf, &typestruct); 12710d7ccabSJulian Elischer 12810d7ccabSJulian Elischer /* Information we store for each hook on each node */ 12910d7ccabSJulian Elischer struct ETF_hookinfo { 13010d7ccabSJulian Elischer hook_p hook; 13110d7ccabSJulian Elischer }; 13210d7ccabSJulian Elischer 13310d7ccabSJulian Elischer struct filter { 13410d7ccabSJulian Elischer LIST_ENTRY(filter) next; 13510d7ccabSJulian Elischer u_int16_t ethertype; /* network order ethertype */ 13610d7ccabSJulian Elischer hook_p match_hook; /* Hook to use on a match */ 13710d7ccabSJulian Elischer }; 13810d7ccabSJulian Elischer 13910d7ccabSJulian Elischer #define HASHSIZE 16 /* Dont change this without changing HASH() */ 14010d7ccabSJulian Elischer #define HASH(et) ((((et)>>12)+((et)>>8)+((et)>>4)+(et)) & 0x0f) 14110d7ccabSJulian Elischer LIST_HEAD(filterhead, filter); 14210d7ccabSJulian Elischer 14310d7ccabSJulian Elischer /* Information we store for each node */ 14410d7ccabSJulian Elischer struct ETF { 14510d7ccabSJulian Elischer struct ETF_hookinfo downstream_hook; 14610d7ccabSJulian Elischer struct ETF_hookinfo nomatch_hook; 14710d7ccabSJulian Elischer node_p node; /* back pointer to node */ 14810d7ccabSJulian Elischer u_int packets_in; /* packets in from downstream */ 14910d7ccabSJulian Elischer u_int packets_out; /* packets out towards downstream */ 15010d7ccabSJulian Elischer u_int32_t flags; 15110d7ccabSJulian Elischer struct filterhead hashtable[HASHSIZE]; 15210d7ccabSJulian Elischer }; 15310d7ccabSJulian Elischer typedef struct ETF *etf_p; 15410d7ccabSJulian Elischer 15510d7ccabSJulian Elischer static struct filter * 15610d7ccabSJulian Elischer ng_etf_findentry(etf_p etfp, u_int16_t ethertype) 15710d7ccabSJulian Elischer { 15810d7ccabSJulian Elischer struct filterhead *chain = etfp->hashtable + HASH(ethertype); 15910d7ccabSJulian Elischer struct filter *fil; 16010d7ccabSJulian Elischer 16110d7ccabSJulian Elischer 16210d7ccabSJulian Elischer LIST_FOREACH(fil, chain, next) { 16310d7ccabSJulian Elischer if (fil->ethertype == ethertype) { 16410d7ccabSJulian Elischer return (fil); 16510d7ccabSJulian Elischer } 16610d7ccabSJulian Elischer } 16710d7ccabSJulian Elischer return (NULL); 16810d7ccabSJulian Elischer } 16910d7ccabSJulian Elischer 17010d7ccabSJulian Elischer 17110d7ccabSJulian Elischer /* 17210d7ccabSJulian Elischer * Allocate the private data structure. The generic node has already 17310d7ccabSJulian Elischer * been created. Link them together. We arrive with a reference to the node 17410d7ccabSJulian Elischer * i.e. the reference count is incremented for us already. 17510d7ccabSJulian Elischer */ 17610d7ccabSJulian Elischer static int 17710d7ccabSJulian Elischer ng_etf_constructor(node_p node) 17810d7ccabSJulian Elischer { 17910d7ccabSJulian Elischer etf_p privdata; 18010d7ccabSJulian Elischer int i; 18110d7ccabSJulian Elischer 18210d7ccabSJulian Elischer /* Initialize private descriptor */ 18310d7ccabSJulian Elischer MALLOC(privdata, etf_p, sizeof(*privdata), M_NETGRAPH_ETF, 18410d7ccabSJulian Elischer M_NOWAIT | M_ZERO); 18510d7ccabSJulian Elischer if (privdata == NULL) 18610d7ccabSJulian Elischer return (ENOMEM); 18710d7ccabSJulian Elischer for (i = 0; i < HASHSIZE; i++) { 18810d7ccabSJulian Elischer LIST_INIT((privdata->hashtable + i)); 18910d7ccabSJulian Elischer } 19010d7ccabSJulian Elischer 19110d7ccabSJulian Elischer /* Link structs together; this counts as our one reference to node */ 19210d7ccabSJulian Elischer NG_NODE_SET_PRIVATE(node, privdata); 19310d7ccabSJulian Elischer privdata->node = node; 19410d7ccabSJulian Elischer return (0); 19510d7ccabSJulian Elischer } 19610d7ccabSJulian Elischer 19710d7ccabSJulian Elischer /* 19810d7ccabSJulian Elischer * Give our ok for a hook to be added... 19910d7ccabSJulian Elischer * All names are ok. Two names are special. 20010d7ccabSJulian Elischer */ 20110d7ccabSJulian Elischer static int 20210d7ccabSJulian Elischer ng_etf_newhook(node_p node, hook_p hook, const char *name) 20310d7ccabSJulian Elischer { 20410d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(node); 20510d7ccabSJulian Elischer struct ETF_hookinfo *hpriv; 20610d7ccabSJulian Elischer 20710d7ccabSJulian Elischer if (strcmp(name, NG_ETF_HOOK_DOWNSTREAM) == 0) { 20810d7ccabSJulian Elischer etfp->downstream_hook.hook = hook; 20910d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, &etfp->downstream_hook); 21010d7ccabSJulian Elischer etfp->packets_in = 0; 21110d7ccabSJulian Elischer etfp->packets_out = 0; 21210d7ccabSJulian Elischer } else if (strcmp(name, NG_ETF_HOOK_NOMATCH) == 0) { 21310d7ccabSJulian Elischer etfp->nomatch_hook.hook = hook; 21410d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, &etfp->nomatch_hook); 21510d7ccabSJulian Elischer } else { 21610d7ccabSJulian Elischer /* 21710d7ccabSJulian Elischer * Any other hook name is valid and can 21810d7ccabSJulian Elischer * later be associated with a filter rule. 21910d7ccabSJulian Elischer */ 22010d7ccabSJulian Elischer MALLOC(hpriv, struct ETF_hookinfo *, sizeof(*hpriv), 22110d7ccabSJulian Elischer M_NETGRAPH_ETF, M_NOWAIT | M_ZERO); 22210d7ccabSJulian Elischer if (hpriv == NULL) { 22310d7ccabSJulian Elischer return (ENOMEM); 22410d7ccabSJulian Elischer } 22510d7ccabSJulian Elischer 22610d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, hpriv); 22710d7ccabSJulian Elischer hpriv->hook = hook; 22810d7ccabSJulian Elischer } 22910d7ccabSJulian Elischer return(0); 23010d7ccabSJulian Elischer } 23110d7ccabSJulian Elischer 23210d7ccabSJulian Elischer /* 23310d7ccabSJulian Elischer * Get a netgraph control message. 23410d7ccabSJulian Elischer * We actually recieve a queue item that has a pointer to the message. 23510d7ccabSJulian Elischer * If we free the item, the message will be freed too, unless we remove 23610d7ccabSJulian Elischer * it from the item using NGI_GET_MSG(); 23710d7ccabSJulian Elischer * The return address is also stored in the item, as an ng_ID_t, 23810d7ccabSJulian Elischer * accessible as NGI_RETADDR(item); 23910d7ccabSJulian Elischer * Check it is one we understand. If needed, send a response. 24010d7ccabSJulian Elischer * We could save the address for an async action later, but don't here. 24110d7ccabSJulian Elischer * Always free the message. 24210d7ccabSJulian Elischer * The response should be in a malloc'd region that the caller can 'free'. 24310d7ccabSJulian Elischer * The NG_MKRESPONSE macro does all this for us. 24410d7ccabSJulian Elischer * A response is not required. 24510d7ccabSJulian Elischer * Theoretically you could respond defferently to old message types if 24610d7ccabSJulian Elischer * the cookie in the header didn't match what we consider to be current 24710d7ccabSJulian Elischer * (so that old userland programs could continue to work). 24810d7ccabSJulian Elischer */ 24910d7ccabSJulian Elischer static int 25010d7ccabSJulian Elischer ng_etf_rcvmsg(node_p node, item_p item, hook_p lasthook) 25110d7ccabSJulian Elischer { 25210d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(node); 25310d7ccabSJulian Elischer struct ng_mesg *resp = NULL; 25410d7ccabSJulian Elischer int error = 0; 25510d7ccabSJulian Elischer struct ng_mesg *msg; 25610d7ccabSJulian Elischer 25710d7ccabSJulian Elischer NGI_GET_MSG(item, msg); 25810d7ccabSJulian Elischer /* Deal with message according to cookie and command */ 25910d7ccabSJulian Elischer switch (msg->header.typecookie) { 26010d7ccabSJulian Elischer case NGM_ETF_COOKIE: 26110d7ccabSJulian Elischer switch (msg->header.cmd) { 26210d7ccabSJulian Elischer case NGM_ETF_GET_STATUS: 26310d7ccabSJulian Elischer { 26410d7ccabSJulian Elischer struct ng_etfstat *stats; 26510d7ccabSJulian Elischer 26610d7ccabSJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); 26710d7ccabSJulian Elischer if (!resp) { 26810d7ccabSJulian Elischer error = ENOMEM; 26910d7ccabSJulian Elischer break; 27010d7ccabSJulian Elischer } 27110d7ccabSJulian Elischer stats = (struct ng_etfstat *) resp->data; 27210d7ccabSJulian Elischer stats->packets_in = etfp->packets_in; 27310d7ccabSJulian Elischer stats->packets_out = etfp->packets_out; 27410d7ccabSJulian Elischer break; 27510d7ccabSJulian Elischer } 27610d7ccabSJulian Elischer case NGM_ETF_SET_FLAG: 27710d7ccabSJulian Elischer if (msg->header.arglen != sizeof(u_int32_t)) { 27810d7ccabSJulian Elischer error = EINVAL; 27910d7ccabSJulian Elischer break; 28010d7ccabSJulian Elischer } 28110d7ccabSJulian Elischer etfp->flags = *((u_int32_t *) msg->data); 28210d7ccabSJulian Elischer break; 28310d7ccabSJulian Elischer case NGM_ETF_SET_FILTER: 28410d7ccabSJulian Elischer { 28510d7ccabSJulian Elischer struct ng_etffilter *f; 28610d7ccabSJulian Elischer struct filter *fil; 28710d7ccabSJulian Elischer hook_p hook; 28810d7ccabSJulian Elischer 28910d7ccabSJulian Elischer /* Check message long enough for this command */ 29010d7ccabSJulian Elischer if (msg->header.arglen != sizeof(*f)) { 29110d7ccabSJulian Elischer error = EINVAL; 29210d7ccabSJulian Elischer break; 29310d7ccabSJulian Elischer } 29410d7ccabSJulian Elischer 29510d7ccabSJulian Elischer /* Make sure hook referenced exists */ 29610d7ccabSJulian Elischer f = (struct ng_etffilter *)msg->data; 29710d7ccabSJulian Elischer hook = ng_findhook(node, f->matchhook); 29810d7ccabSJulian Elischer if (hook == NULL) { 29910d7ccabSJulian Elischer error = ENOENT; 30010d7ccabSJulian Elischer break; 30110d7ccabSJulian Elischer } 30210d7ccabSJulian Elischer 30310d7ccabSJulian Elischer /* and is not the downstream hook */ 30410d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 30510d7ccabSJulian Elischer error = EINVAL; 30610d7ccabSJulian Elischer break; 30710d7ccabSJulian Elischer } 30810d7ccabSJulian Elischer 30910d7ccabSJulian Elischer /* Check we don't already trap this ethertype */ 31010d7ccabSJulian Elischer if (ng_etf_findentry(etfp, 31110d7ccabSJulian Elischer htons(f->ethertype))) { 31210d7ccabSJulian Elischer error = EEXIST; 31310d7ccabSJulian Elischer break; 31410d7ccabSJulian Elischer } 31510d7ccabSJulian Elischer 31610d7ccabSJulian Elischer /* 31710d7ccabSJulian Elischer * Ok, make the filter and put it in the 31810d7ccabSJulian Elischer * hashtable ready for matching. 31910d7ccabSJulian Elischer */ 32010d7ccabSJulian Elischer MALLOC(fil, struct filter *, sizeof(*fil), 32110d7ccabSJulian Elischer M_NETGRAPH_ETF, M_NOWAIT | M_ZERO); 32210d7ccabSJulian Elischer if (fil == NULL) { 323cdea8b85SRuslan Ermilov error = ENOMEM; 324cdea8b85SRuslan Ermilov break; 32510d7ccabSJulian Elischer } 32610d7ccabSJulian Elischer 32710d7ccabSJulian Elischer fil->match_hook = hook; 32810d7ccabSJulian Elischer fil->ethertype = htons(f->ethertype); 32910d7ccabSJulian Elischer LIST_INSERT_HEAD( etfp->hashtable 33010d7ccabSJulian Elischer + HASH(fil->ethertype), 33110d7ccabSJulian Elischer fil, next); 33210d7ccabSJulian Elischer } 33310d7ccabSJulian Elischer break; 33410d7ccabSJulian Elischer default: 33510d7ccabSJulian Elischer error = EINVAL; /* unknown command */ 33610d7ccabSJulian Elischer break; 33710d7ccabSJulian Elischer } 33810d7ccabSJulian Elischer break; 33910d7ccabSJulian Elischer default: 34010d7ccabSJulian Elischer error = EINVAL; /* unknown cookie type */ 34110d7ccabSJulian Elischer break; 34210d7ccabSJulian Elischer } 34310d7ccabSJulian Elischer 34410d7ccabSJulian Elischer /* Take care of synchronous response, if any */ 34510d7ccabSJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 34610d7ccabSJulian Elischer /* Free the message and return */ 34710d7ccabSJulian Elischer NG_FREE_MSG(msg); 34810d7ccabSJulian Elischer return(error); 34910d7ccabSJulian Elischer } 35010d7ccabSJulian Elischer 35110d7ccabSJulian Elischer /* 35210d7ccabSJulian Elischer * Receive data, and do something with it. 35310d7ccabSJulian Elischer * Actually we receive a queue item which holds the data. 35410d7ccabSJulian Elischer * If we free the item it wil also froo the data and metadata unless 35510d7ccabSJulian Elischer * we have previously disassociated them using the NGI_GET_etf() macros. 35610d7ccabSJulian Elischer * Possibly send it out on another link after processing. 35710d7ccabSJulian Elischer * Possibly do something different if it comes from different 35810d7ccabSJulian Elischer * hooks. the caller will never free m or meta, so 35910d7ccabSJulian Elischer * if we use up this data or abort we must free BOTH of these. 36010d7ccabSJulian Elischer * 36110d7ccabSJulian Elischer * If we want, we may decide to force this data to be queued and reprocessed 36210d7ccabSJulian Elischer * at the netgraph NETISR time. 36310d7ccabSJulian Elischer * We would do that by setting the HK_QUEUE flag on our hook. We would do that 36410d7ccabSJulian Elischer * in the connect() method. 36510d7ccabSJulian Elischer */ 36610d7ccabSJulian Elischer static int 36710d7ccabSJulian Elischer ng_etf_rcvdata(hook_p hook, item_p item ) 36810d7ccabSJulian Elischer { 36910d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 37010d7ccabSJulian Elischer struct ether_header *eh; 37110d7ccabSJulian Elischer int error = 0; 37210d7ccabSJulian Elischer struct mbuf *m; 37310d7ccabSJulian Elischer u_int16_t ethertype; 37410d7ccabSJulian Elischer struct filter *fil; 37510d7ccabSJulian Elischer 37610d7ccabSJulian Elischer if (NG_HOOK_PRIVATE(hook) == NULL) { /* Shouldn't happen but.. */ 37710d7ccabSJulian Elischer NG_FREE_ITEM(item); 37810d7ccabSJulian Elischer } 37910d7ccabSJulian Elischer 38010d7ccabSJulian Elischer /* 38110d7ccabSJulian Elischer * Everything not from the downstream hook goes to the 38210d7ccabSJulian Elischer * downstream hook. But only if it matches the ethertype 38310d7ccabSJulian Elischer * of the source hook. Un matching must go to/from 'nomatch'. 38410d7ccabSJulian Elischer */ 38510d7ccabSJulian Elischer 38610d7ccabSJulian Elischer /* Make sure we have an entire header */ 38710d7ccabSJulian Elischer NGI_GET_M(item, m); 38810d7ccabSJulian Elischer if (m->m_len < sizeof(*eh) ) { 38910d7ccabSJulian Elischer m = m_pullup(m, sizeof(*eh)); 39010d7ccabSJulian Elischer if (m == NULL) { 39110d7ccabSJulian Elischer NG_FREE_ITEM(item); 39210d7ccabSJulian Elischer return(EINVAL); 39310d7ccabSJulian Elischer } 39410d7ccabSJulian Elischer } 39510d7ccabSJulian Elischer 39610d7ccabSJulian Elischer eh = mtod(m, struct ether_header *); 39710d7ccabSJulian Elischer ethertype = eh->ether_type; 39810d7ccabSJulian Elischer fil = ng_etf_findentry(etfp, ethertype); 39910d7ccabSJulian Elischer 40010d7ccabSJulian Elischer /* 40110d7ccabSJulian Elischer * if from downstream, select between a match hook or 40210d7ccabSJulian Elischer * the nomatch hook 40310d7ccabSJulian Elischer */ 40410d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 40510d7ccabSJulian Elischer etfp->packets_in++; 40610d7ccabSJulian Elischer if (fil && fil->match_hook) { 40710d7ccabSJulian Elischer NG_FWD_NEW_DATA(error, item, fil->match_hook, m); 40810d7ccabSJulian Elischer } else { 40910d7ccabSJulian Elischer NG_FWD_NEW_DATA(error, item,etfp->nomatch_hook.hook, m); 41010d7ccabSJulian Elischer } 41110d7ccabSJulian Elischer } else { 41210d7ccabSJulian Elischer /* 41310d7ccabSJulian Elischer * It must be heading towards the downstream. 41410d7ccabSJulian Elischer * Check that it's ethertype matches 41510d7ccabSJulian Elischer * the filters for it's input hook. 41610d7ccabSJulian Elischer * If it doesn't have one, check it's from nomatch. 41710d7ccabSJulian Elischer */ 41810d7ccabSJulian Elischer if ((fil && (fil->match_hook != hook)) 41910d7ccabSJulian Elischer || ((fil == NULL) && (hook != etfp->nomatch_hook.hook))) { 42010d7ccabSJulian Elischer NG_FREE_ITEM(item); 42110d7ccabSJulian Elischer NG_FREE_M(m); 42210d7ccabSJulian Elischer return (EPROTOTYPE); 42310d7ccabSJulian Elischer } 42410d7ccabSJulian Elischer NG_FWD_NEW_DATA( error, item, etfp->downstream_hook.hook, m); 42510d7ccabSJulian Elischer if (error == 0) { 42610d7ccabSJulian Elischer etfp->packets_out++; 42710d7ccabSJulian Elischer } 42810d7ccabSJulian Elischer } 42910d7ccabSJulian Elischer return (error); 43010d7ccabSJulian Elischer } 43110d7ccabSJulian Elischer 43210d7ccabSJulian Elischer /* 43310d7ccabSJulian Elischer * Do local shutdown processing.. 43410d7ccabSJulian Elischer * All our links and the name have already been removed. 43510d7ccabSJulian Elischer */ 43610d7ccabSJulian Elischer static int 43710d7ccabSJulian Elischer ng_etf_shutdown(node_p node) 43810d7ccabSJulian Elischer { 43910d7ccabSJulian Elischer const etf_p privdata = NG_NODE_PRIVATE(node); 44010d7ccabSJulian Elischer 44110d7ccabSJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 44210d7ccabSJulian Elischer NG_NODE_UNREF(privdata->node); 44310d7ccabSJulian Elischer FREE(privdata, M_NETGRAPH_ETF); 44410d7ccabSJulian Elischer return (0); 44510d7ccabSJulian Elischer } 44610d7ccabSJulian Elischer 44710d7ccabSJulian Elischer /* 44810d7ccabSJulian Elischer * This is called once we've already connected a new hook to the other node. 44910d7ccabSJulian Elischer * It gives us a chance to balk at the last minute. 45010d7ccabSJulian Elischer */ 45110d7ccabSJulian Elischer static int 45210d7ccabSJulian Elischer ng_etf_connect(hook_p hook) 45310d7ccabSJulian Elischer { 45410d7ccabSJulian Elischer return (0); 45510d7ccabSJulian Elischer } 45610d7ccabSJulian Elischer 45710d7ccabSJulian Elischer /* 45810d7ccabSJulian Elischer * Hook disconnection 45910d7ccabSJulian Elischer * 46010d7ccabSJulian Elischer * For this type, removal of the last link destroys the node 46110d7ccabSJulian Elischer */ 46210d7ccabSJulian Elischer static int 46310d7ccabSJulian Elischer ng_etf_disconnect(hook_p hook) 46410d7ccabSJulian Elischer { 46510d7ccabSJulian Elischer const etf_p etfp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 46610d7ccabSJulian Elischer int i; 46705f768d9SRuslan Ermilov struct filter *fil1, *fil2; 46810d7ccabSJulian Elischer 46910d7ccabSJulian Elischer /* purge any rules that refer to this filter */ 47010d7ccabSJulian Elischer for (i = 0; i < HASHSIZE; i++) { 47105f768d9SRuslan Ermilov fil1 = LIST_FIRST(&etfp->hashtable[i]); 47205f768d9SRuslan Ermilov while (fil1 != NULL) { 47305f768d9SRuslan Ermilov fil2 = LIST_NEXT(fil1, next); 47405f768d9SRuslan Ermilov if (fil1->match_hook == hook) { 47505f768d9SRuslan Ermilov LIST_REMOVE(fil1, next); 47605f768d9SRuslan Ermilov FREE(fil1, M_NETGRAPH_ETF); 47710d7ccabSJulian Elischer } 47805f768d9SRuslan Ermilov fil1 = fil2; 47910d7ccabSJulian Elischer } 48010d7ccabSJulian Elischer } 48110d7ccabSJulian Elischer 48210d7ccabSJulian Elischer /* If it's not one of the special hooks, then free it */ 48310d7ccabSJulian Elischer if (hook == etfp->downstream_hook.hook) { 48410d7ccabSJulian Elischer etfp->downstream_hook.hook = NULL; 48510d7ccabSJulian Elischer } else if (hook == etfp->nomatch_hook.hook) { 48610d7ccabSJulian Elischer etfp->nomatch_hook.hook = NULL; 48710d7ccabSJulian Elischer } else { 48810d7ccabSJulian Elischer if (NG_HOOK_PRIVATE(hook)) /* Paranoia */ 48910d7ccabSJulian Elischer FREE(NG_HOOK_PRIVATE(hook), M_NETGRAPH_ETF); 49010d7ccabSJulian Elischer } 49110d7ccabSJulian Elischer 49210d7ccabSJulian Elischer NG_HOOK_SET_PRIVATE(hook, NULL); 49310d7ccabSJulian Elischer 49410d7ccabSJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 49510d7ccabSJulian Elischer && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) /* already shutting down? */ 49610d7ccabSJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook)); 49710d7ccabSJulian Elischer return (0); 49810d7ccabSJulian Elischer } 49910d7ccabSJulian Elischer 500