ng_ether.c revision 62143
162143Sarchie 262143Sarchie/* 362143Sarchie * ng_ether.c 462143Sarchie * 562143Sarchie * Copyright (c) 1996-2000 Whistle Communications, Inc. 662143Sarchie * All rights reserved. 762143Sarchie * 862143Sarchie * Subject to the following obligations and disclaimer of warranty, use and 962143Sarchie * redistribution of this software, in source or object code forms, with or 1062143Sarchie * without modifications are expressly permitted by Whistle Communications; 1162143Sarchie * provided, however, that: 1262143Sarchie * 1. Any and all reproductions of the source or object code must include the 1362143Sarchie * copyright notice above and the following disclaimer of warranties; and 1462143Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1562143Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1662143Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1762143Sarchie * such appears in the above copyright notice or in the software. 1862143Sarchie * 1962143Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2062143Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2162143Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2262143Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2362143Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2462143Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2562143Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2662143Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2762143Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2862143Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2962143Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3062143Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3162143Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3262143Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3362143Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3462143Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3562143Sarchie * OF SUCH DAMAGE. 3662143Sarchie * 3762143Sarchie * Authors: Archie Cobbs <archie@freebsd.org> 3862143Sarchie * Julian Elischer <julian@freebsd.org> 3962143Sarchie * 4062143Sarchie * $FreeBSD: head/sys/netgraph/ng_ether.c 62143 2000-06-26 23:34:54Z archie $ 4162143Sarchie */ 4262143Sarchie 4362143Sarchie/* 4462143Sarchie * ng_ether(4) netgraph node type 4562143Sarchie */ 4662143Sarchie 4762143Sarchie#include <sys/param.h> 4862143Sarchie#include <sys/systm.h> 4962143Sarchie#include <sys/kernel.h> 5062143Sarchie#include <sys/malloc.h> 5162143Sarchie#include <sys/mbuf.h> 5262143Sarchie#include <sys/errno.h> 5362143Sarchie#include <sys/syslog.h> 5462143Sarchie#include <sys/socket.h> 5562143Sarchie 5662143Sarchie#include <net/if.h> 5762143Sarchie#include <net/if_types.h> 5862143Sarchie#include <net/if_arp.h> 5962143Sarchie#include <net/if_var.h> 6062143Sarchie#include <net/ethernet.h> 6162143Sarchie 6262143Sarchie#include <netgraph/ng_message.h> 6362143Sarchie#include <netgraph/netgraph.h> 6462143Sarchie#include <netgraph/ng_parse.h> 6562143Sarchie#include <netgraph/ng_ether.h> 6662143Sarchie 6762143Sarchie#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph) 6862143Sarchie 6962143Sarchie/* Per-node private data */ 7062143Sarchiestruct private { 7162143Sarchie struct ifnet *ifp; /* associated interface */ 7262143Sarchie hook_p upper; /* upper hook connection */ 7362143Sarchie hook_p lower; /* lower OR orphan hook connection */ 7462143Sarchie u_char lowerOrphan; /* whether lower is lower or orphan */ 7562143Sarchie}; 7662143Sarchietypedef struct private *priv_p; 7762143Sarchie 7862143Sarchie/* Functional hooks called from if_ethersubr.c */ 7962143Sarchiestatic void ng_ether_input(struct ifnet *ifp, 8062143Sarchie struct mbuf **mp, struct ether_header *eh); 8162143Sarchiestatic void ng_ether_input_orphan(struct ifnet *ifp, 8262143Sarchie struct mbuf *m, struct ether_header *eh); 8362143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 8462143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 8562143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 8662143Sarchie 8762143Sarchie/* Other functions */ 8862143Sarchiestatic void ng_ether_input2(node_p node, 8962143Sarchie struct mbuf **mp, struct ether_header *eh); 9062143Sarchiestatic int ng_ether_glueback_header(struct mbuf **mp, 9162143Sarchie struct ether_header *eh); 9262143Sarchiestatic int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 9362143Sarchiestatic int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 9462143Sarchie 9562143Sarchie/* Netgraph node methods */ 9662143Sarchiestatic ng_constructor_t ng_ether_constructor; 9762143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 9862143Sarchiestatic ng_shutdown_t ng_ether_rmnode; 9962143Sarchiestatic ng_newhook_t ng_ether_newhook; 10062143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10162143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 10262143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 10362143Sarchie 10462143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 10562143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 10662143Sarchie { 10762143Sarchie NGM_ETHER_COOKIE, 10862143Sarchie NGM_ETHER_GET_IFNAME, 10962143Sarchie "getifname", 11062143Sarchie NULL, 11162143Sarchie &ng_parse_string_type 11262143Sarchie }, 11362143Sarchie { 11462143Sarchie NGM_ETHER_COOKIE, 11562143Sarchie NGM_ETHER_GET_IFINDEX, 11662143Sarchie "getifindex", 11762143Sarchie NULL, 11862143Sarchie &ng_parse_int32_type 11962143Sarchie }, 12062143Sarchie { 0 } 12162143Sarchie}; 12262143Sarchie 12362143Sarchiestatic struct ng_type ng_ether_typestruct = { 12462143Sarchie NG_VERSION, 12562143Sarchie NG_ETHER_NODE_TYPE, 12662143Sarchie ng_ether_mod_event, 12762143Sarchie ng_ether_constructor, 12862143Sarchie ng_ether_rcvmsg, 12962143Sarchie ng_ether_rmnode, 13062143Sarchie ng_ether_newhook, 13162143Sarchie NULL, 13262143Sarchie NULL, 13362143Sarchie ng_ether_rcvdata, 13462143Sarchie ng_ether_rcvdata, 13562143Sarchie ng_ether_disconnect, 13662143Sarchie ng_ether_cmdlist, 13762143Sarchie}; 13862143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 13962143Sarchie 14062143Sarchie/****************************************************************** 14162143Sarchie ETHERNET FUNCTION HOOKS 14262143Sarchie******************************************************************/ 14362143Sarchie 14462143Sarchie/* 14562143Sarchie * Handle a packet that has come in on an interface. We get to 14662143Sarchie * look at it here before any upper layer protocols do. 14762143Sarchie * 14862143Sarchie * NOTE: this function will get called at splimp() 14962143Sarchie */ 15062143Sarchiestatic void 15162143Sarchieng_ether_input(struct ifnet *ifp, 15262143Sarchie struct mbuf **mp, struct ether_header *eh) 15362143Sarchie{ 15462143Sarchie const node_p node = IFP2NG(ifp); 15562143Sarchie const priv_p priv = node->private; 15662143Sarchie 15762143Sarchie /* If "lower" hook not connected, let packet continue */ 15862143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 15962143Sarchie return; 16062143Sarchie ng_ether_input2(node, mp, eh); 16162143Sarchie} 16262143Sarchie 16362143Sarchie/* 16462143Sarchie * Handle a packet that has come in on an interface, and which 16562143Sarchie * does not match any of our known protocols (an ``orphan''). 16662143Sarchie * 16762143Sarchie * NOTE: this function will get called at splimp() 16862143Sarchie */ 16962143Sarchiestatic void 17062143Sarchieng_ether_input_orphan(struct ifnet *ifp, 17162143Sarchie struct mbuf *m, struct ether_header *eh) 17262143Sarchie{ 17362143Sarchie const node_p node = IFP2NG(ifp); 17462143Sarchie const priv_p priv = node->private; 17562143Sarchie 17662143Sarchie /* If "orphan" hook not connected, let packet continue */ 17762143Sarchie if (priv->lower == NULL || !priv->lowerOrphan) { 17862143Sarchie m_freem(m); 17962143Sarchie return; 18062143Sarchie } 18162143Sarchie ng_ether_input2(node, &m, eh); 18262143Sarchie if (m != NULL) 18362143Sarchie m_freem(m); 18462143Sarchie} 18562143Sarchie 18662143Sarchie/* 18762143Sarchie * Handle a packet that has come in on an interface. 18862143Sarchie * The Ethernet header has already been detached from the mbuf, 18962143Sarchie * so we have to put it back. 19062143Sarchie * 19162143Sarchie * NOTE: this function will get called at splimp() 19262143Sarchie */ 19362143Sarchiestatic void 19462143Sarchieng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh) 19562143Sarchie{ 19662143Sarchie const priv_p priv = node->private; 19762143Sarchie meta_p meta = NULL; 19862143Sarchie int error; 19962143Sarchie 20062143Sarchie /* Glue Ethernet header back on */ 20162143Sarchie if ((error = ng_ether_glueback_header(mp, eh)) != 0) 20262143Sarchie return; 20362143Sarchie 20462143Sarchie /* Send out lower/orphan hook */ 20562143Sarchie NG_SEND_DATAQ(error, priv->lower, *mp, meta); 20662143Sarchie 20762143Sarchie /* Any reflected packet must come later due to queuing */ 20862143Sarchie *mp = NULL; 20962143Sarchie} 21062143Sarchie 21162143Sarchie/* 21262143Sarchie * Handle a packet that is going out on an interface. 21362143Sarchie * The Ethernet header is already attached to the mbuf. 21462143Sarchie */ 21562143Sarchiestatic int 21662143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 21762143Sarchie{ 21862143Sarchie const node_p node = IFP2NG(ifp); 21962143Sarchie const priv_p priv = node->private; 22062143Sarchie meta_p meta = NULL; 22162143Sarchie int error = 0; 22262143Sarchie 22362143Sarchie /* If "upper" hook not connected, let packet continue */ 22462143Sarchie if (priv->upper == NULL) 22562143Sarchie return (0); 22662143Sarchie 22762143Sarchie /* Send it out "upper" hook */ 22862143Sarchie NG_SEND_DATA_RET(error, priv->upper, *mp, meta); 22962143Sarchie 23062143Sarchie /* If we got a reflected packet back, handle it */ 23162143Sarchie if (error == 0 && *mp != NULL) { 23262143Sarchie error = ng_ether_rcv_upper(node, *mp, meta); 23362143Sarchie *mp = NULL; 23462143Sarchie } 23562143Sarchie return (error); 23662143Sarchie} 23762143Sarchie 23862143Sarchie/* 23962143Sarchie * A new Ethernet interface has been attached. 24062143Sarchie * Create a new node for it, etc. 24162143Sarchie */ 24262143Sarchiestatic void 24362143Sarchieng_ether_attach(struct ifnet *ifp) 24462143Sarchie{ 24562143Sarchie char name[IFNAMSIZ + 1]; 24662143Sarchie priv_p priv; 24762143Sarchie node_p node; 24862143Sarchie 24962143Sarchie /* Create node */ 25062143Sarchie KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__)); 25162143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 25262143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 25362143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 25462143Sarchie __FUNCTION__, "create node", name); 25562143Sarchie return; 25662143Sarchie } 25762143Sarchie 25862143Sarchie /* Allocate private data */ 25962143Sarchie MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT); 26062143Sarchie if (priv == NULL) { 26162143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 26262143Sarchie __FUNCTION__, "allocate memory", name); 26362143Sarchie ng_unref(node); 26462143Sarchie return; 26562143Sarchie } 26662143Sarchie bzero(priv, sizeof(*priv)); 26762143Sarchie node->private = priv; 26862143Sarchie priv->ifp = ifp; 26962143Sarchie IFP2NG(ifp) = node; 27062143Sarchie 27162143Sarchie /* Try to give the node the same name as the interface */ 27262143Sarchie if (ng_name_node(node, name) != 0) { 27362143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 27462143Sarchie __FUNCTION__, name); 27562143Sarchie } 27662143Sarchie} 27762143Sarchie 27862143Sarchie/* 27962143Sarchie * An Ethernet interface is being detached. 28062143Sarchie * Destroy its node. 28162143Sarchie */ 28262143Sarchiestatic void 28362143Sarchieng_ether_detach(struct ifnet *ifp) 28462143Sarchie{ 28562143Sarchie const node_p node = IFP2NG(ifp); 28662143Sarchie priv_p priv; 28762143Sarchie 28862143Sarchie if (node == NULL) /* no node (why not?), ignore */ 28962143Sarchie return; 29062143Sarchie ng_rmnode(node); /* break all links to other nodes */ 29162143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 29262143Sarchie priv = node->private; /* free node private info */ 29362143Sarchie bzero(priv, sizeof(*priv)); 29462143Sarchie FREE(priv, M_NETGRAPH); 29562143Sarchie node->private = NULL; 29662143Sarchie ng_unref(node); /* free node itself */ 29762143Sarchie} 29862143Sarchie 29962143Sarchie/* 30062143Sarchie * Optimization for gluing the Ethernet header back onto 30162143Sarchie * the front of an incoming packet. 30262143Sarchie */ 30362143Sarchiestatic int 30462143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 30562143Sarchie{ 30662143Sarchie struct mbuf *m = *mp; 30762143Sarchie uintfptr_t room; 30862143Sarchie int error = 0; 30962143Sarchie 31062143Sarchie /* 31162143Sarchie * Possibly the header is already on the front. 31262143Sarchie * If this is the case so just move the markers back 31362143Sarchie * to re-include it. We lucked out. 31462143Sarchie * This allows us to avoid a yucky m_pullup 31562143Sarchie * in later nodes if it works. 31662143Sarchie */ 31762143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 31862143Sarchie m->m_len += sizeof(*eh); 31962143Sarchie m->m_data -= sizeof(*eh); 32062143Sarchie m->m_pkthdr.len += sizeof(*eh); 32162143Sarchie goto done; 32262143Sarchie } 32362143Sarchie 32462143Sarchie /* 32562143Sarchie * Alternatively there may be room even though 32662143Sarchie * it is stored somewhere else. If so, copy it in. 32762143Sarchie * This only safe because we KNOW that this packet has 32862143Sarchie * just been generated by an ethernet card, so there are 32962143Sarchie * no aliases to the buffer (not so for outgoing packets). 33062143Sarchie * Nearly all ethernet cards will end up producing mbufs 33162143Sarchie * that fall into these cases. So we are not optimizing 33262143Sarchie * contorted cases. 33362143Sarchie */ 33462143Sarchie if ((m->m_flags & M_EXT) != 0) { 33562143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 33662143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 33762143Sarchie room = 0; 33862143Sarchie } else 33962143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 34062143Sarchie 34162143Sarchie /* 34262143Sarchie * If we have room, just copy it and adjust 34362143Sarchie */ 34462143Sarchie if (room >= sizeof(*eh)) { 34562143Sarchie m->m_len += sizeof(*eh); 34662143Sarchie m->m_data -= sizeof(*eh); 34762143Sarchie m->m_pkthdr.len += sizeof(*eh); 34862143Sarchie goto copy; 34962143Sarchie } 35062143Sarchie 35162143Sarchie /* 35262143Sarchie * Doing anything more is likely to get more 35362143Sarchie * expensive than it's worth.. 35462143Sarchie * it's probable that everything else is in one 35562143Sarchie * big lump. The next node will do an m_pullup() 35662143Sarchie * for exactly the amount of data it needs and 35762143Sarchie * hopefully everything after that will not 35862143Sarchie * need one. So let's just use M_PREPEND. 35962143Sarchie */ 36062143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 36162143Sarchie if (m == NULL) { 36262143Sarchie error = ENOBUFS; 36362143Sarchie goto done; 36462143Sarchie } 36562143Sarchie 36662143Sarchiecopy: 36762143Sarchie /* Copy header and return (possibly new) mbuf */ 36862143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 36962143Sarchiedone: 37062143Sarchie *mp = m; 37162143Sarchie return error; 37262143Sarchie} 37362143Sarchie 37462143Sarchie/****************************************************************** 37562143Sarchie NETGRAPH NODE METHODS 37662143Sarchie******************************************************************/ 37762143Sarchie 37862143Sarchie/* 37962143Sarchie * It is not possible or allowable to create a node of this type. 38062143Sarchie * Nodes get created when the interface is attached (or, when 38162143Sarchie * this node type's KLD is loaded). 38262143Sarchie */ 38362143Sarchiestatic int 38462143Sarchieng_ether_constructor(node_p *nodep) 38562143Sarchie{ 38662143Sarchie return (EINVAL); 38762143Sarchie} 38862143Sarchie 38962143Sarchie/* 39062143Sarchie * Check for attaching a new hook. 39162143Sarchie */ 39262143Sarchiestatic int 39362143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 39462143Sarchie{ 39562143Sarchie const priv_p priv = node->private; 39662143Sarchie u_char orphan = priv->lowerOrphan; 39762143Sarchie hook_p *hookptr; 39862143Sarchie 39962143Sarchie /* Divert hook is an alias for lower */ 40062143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 40162143Sarchie name = NG_ETHER_HOOK_LOWER; 40262143Sarchie 40362143Sarchie /* Which hook? */ 40462143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 40562143Sarchie hookptr = &priv->upper; 40662143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 40762143Sarchie hookptr = &priv->lower; 40862143Sarchie orphan = 0; 40962143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 41062143Sarchie hookptr = &priv->lower; 41162143Sarchie orphan = 1; 41262143Sarchie } else 41362143Sarchie return (EINVAL); 41462143Sarchie 41562143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 41662143Sarchie if (*hookptr != NULL) 41762143Sarchie return (EISCONN); 41862143Sarchie 41962143Sarchie /* OK */ 42062143Sarchie *hookptr = hook; 42162143Sarchie priv->lowerOrphan = orphan; 42262143Sarchie return (0); 42362143Sarchie} 42462143Sarchie 42562143Sarchie/* 42662143Sarchie * Receive an incoming control message. 42762143Sarchie */ 42862143Sarchiestatic int 42962143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 43062143Sarchie struct ng_mesg **rptr, hook_p lasthook) 43162143Sarchie{ 43262143Sarchie const priv_p priv = node->private; 43362143Sarchie struct ng_mesg *resp = NULL; 43462143Sarchie int error = 0; 43562143Sarchie 43662143Sarchie switch (msg->header.typecookie) { 43762143Sarchie case NGM_ETHER_COOKIE: 43862143Sarchie switch (msg->header.cmd) { 43962143Sarchie case NGM_ETHER_GET_IFNAME: 44062143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 44162143Sarchie if (resp == NULL) { 44262143Sarchie error = ENOMEM; 44362143Sarchie break; 44462143Sarchie } 44562143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 44662143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 44762143Sarchie break; 44862143Sarchie case NGM_ETHER_GET_IFINDEX: 44962143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 45062143Sarchie if (resp == NULL) { 45162143Sarchie error = ENOMEM; 45262143Sarchie break; 45362143Sarchie } 45462143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 45562143Sarchie break; 45662143Sarchie default: 45762143Sarchie error = EINVAL; 45862143Sarchie break; 45962143Sarchie } 46062143Sarchie break; 46162143Sarchie default: 46262143Sarchie error = EINVAL; 46362143Sarchie break; 46462143Sarchie } 46562143Sarchie if (rptr) 46662143Sarchie *rptr = resp; 46762143Sarchie else if (resp != NULL) 46862143Sarchie FREE(resp, M_NETGRAPH); 46962143Sarchie FREE(msg, M_NETGRAPH); 47062143Sarchie return (error); 47162143Sarchie} 47262143Sarchie 47362143Sarchie/* 47462143Sarchie * Receive data on a hook. 47562143Sarchie */ 47662143Sarchiestatic int 47762143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 47862143Sarchie struct mbuf **ret_m, meta_p *ret_meta) 47962143Sarchie{ 48062143Sarchie const node_p node = hook->node; 48162143Sarchie const priv_p priv = node->private; 48262143Sarchie 48362143Sarchie if (hook == priv->lower) 48462143Sarchie return ng_ether_rcv_lower(node, m, meta); 48562143Sarchie if (hook == priv->upper) 48662143Sarchie return ng_ether_rcv_upper(node, m, meta); 48762143Sarchie panic("%s: weird hook", __FUNCTION__); 48862143Sarchie} 48962143Sarchie 49062143Sarchie/* 49162143Sarchie * Handle an mbuf received on the "lower" hook. 49262143Sarchie */ 49362143Sarchiestatic int 49462143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 49562143Sarchie{ 49662143Sarchie const priv_p priv = node->private; 49762143Sarchie 49862143Sarchie /* Make sure header is fully pulled up */ 49962143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 50062143Sarchie NG_FREE_DATA(m, meta); 50162143Sarchie return (EINVAL); 50262143Sarchie } 50362143Sarchie if (m->m_len < sizeof(struct ether_header) 50462143Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 50562143Sarchie NG_FREE_META(meta); 50662143Sarchie return (ENOBUFS); 50762143Sarchie } 50862143Sarchie 50962143Sarchie /* Send it on its way */ 51062143Sarchie NG_FREE_META(meta); 51162143Sarchie return ether_output_frame(priv->ifp, m); 51262143Sarchie} 51362143Sarchie 51462143Sarchie/* 51562143Sarchie * Handle an mbuf received on the "upper" hook. 51662143Sarchie */ 51762143Sarchiestatic int 51862143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 51962143Sarchie{ 52062143Sarchie const priv_p priv = node->private; 52162143Sarchie struct ether_header *eh; 52262143Sarchie 52362143Sarchie /* Check length and pull off header */ 52462143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 52562143Sarchie NG_FREE_DATA(m, meta); 52662143Sarchie return (EINVAL); 52762143Sarchie } 52862143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 52962143Sarchie NG_FREE_META(meta); 53062143Sarchie return (ENOBUFS); 53162143Sarchie } 53262143Sarchie eh = mtod(m, struct ether_header *); 53362143Sarchie m->m_data += sizeof(*eh); 53462143Sarchie m->m_len -= sizeof(*eh); 53562143Sarchie m->m_pkthdr.len -= sizeof(*eh); 53662143Sarchie 53762143Sarchie /* Route packet back in */ 53862143Sarchie NG_FREE_META(meta); 53962143Sarchie ether_demux(priv->ifp, eh, m); 54062143Sarchie return (0); 54162143Sarchie} 54262143Sarchie 54362143Sarchie/* 54462143Sarchie * Shutdown node. This resets the node but does not remove it. 54562143Sarchie */ 54662143Sarchiestatic int 54762143Sarchieng_ether_rmnode(node_p node) 54862143Sarchie{ 54962143Sarchie ng_cutlinks(node); 55062143Sarchie node->flags &= ~NG_INVALID; /* bounce back to life */ 55162143Sarchie return (0); 55262143Sarchie} 55362143Sarchie 55462143Sarchie/* 55562143Sarchie * Hook disconnection. 55662143Sarchie */ 55762143Sarchiestatic int 55862143Sarchieng_ether_disconnect(hook_p hook) 55962143Sarchie{ 56062143Sarchie const priv_p priv = hook->node->private; 56162143Sarchie 56262143Sarchie if (hook == priv->upper) 56362143Sarchie priv->upper = NULL; 56462143Sarchie else if (hook == priv->lower) { 56562143Sarchie priv->lower = NULL; 56662143Sarchie priv->lowerOrphan = 0; 56762143Sarchie } else 56862143Sarchie panic("%s: weird hook", __FUNCTION__); 56962143Sarchie return (0); 57062143Sarchie} 57162143Sarchie 57262143Sarchie/****************************************************************** 57362143Sarchie INITIALIZATION 57462143Sarchie******************************************************************/ 57562143Sarchie 57662143Sarchie/* 57762143Sarchie * Handle loading and unloading for this node type. 57862143Sarchie */ 57962143Sarchiestatic int 58062143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 58162143Sarchie{ 58262143Sarchie struct ifnet *ifp; 58362143Sarchie int error = 0; 58462143Sarchie int s; 58562143Sarchie 58662143Sarchie s = splnet(); 58762143Sarchie switch (event) { 58862143Sarchie case MOD_LOAD: 58962143Sarchie 59062143Sarchie /* Register function hooks */ 59162143Sarchie if (ng_ether_attach_p != NULL) { 59262143Sarchie error = EEXIST; 59362143Sarchie break; 59462143Sarchie } 59562143Sarchie ng_ether_attach_p = ng_ether_attach; 59662143Sarchie ng_ether_detach_p = ng_ether_detach; 59762143Sarchie ng_ether_output_p = ng_ether_output; 59862143Sarchie ng_ether_input_p = ng_ether_input; 59962143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 60062143Sarchie 60162143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 60262143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 60362143Sarchie if (ifp->if_type == IFT_ETHER) 60462143Sarchie ng_ether_attach(ifp); 60562143Sarchie } 60662143Sarchie break; 60762143Sarchie 60862143Sarchie case MOD_UNLOAD: 60962143Sarchie 61062143Sarchie /* 61162143Sarchie * Note that the base code won't try to unload us until 61262143Sarchie * all nodes have been removed, and that can't happen 61362143Sarchie * until all Ethernet interfaces are removed. In any 61462143Sarchie * case, we know there are no nodes left if the action 61562143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 61662143Sarchie */ 61762143Sarchie 61862143Sarchie /* Unregister function hooks */ 61962143Sarchie ng_ether_attach_p = NULL; 62062143Sarchie ng_ether_detach_p = NULL; 62162143Sarchie ng_ether_output_p = NULL; 62262143Sarchie ng_ether_input_p = NULL; 62362143Sarchie ng_ether_input_orphan_p = NULL; 62462143Sarchie break; 62562143Sarchie 62662143Sarchie default: 62762143Sarchie error = EOPNOTSUPP; 62862143Sarchie break; 62962143Sarchie } 63062143Sarchie splx(s); 63162143Sarchie return (error); 63262143Sarchie} 63362143Sarchie 634