ng_ether.c revision 63053
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 63053 2000-07-12 23:55:07Z 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 6762678Sjulian#define IFP2AC(IFP) ((struct arpcom *)IFP) 6862143Sarchie#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph) 6962143Sarchie 7062143Sarchie/* Per-node private data */ 7162143Sarchiestruct private { 7262143Sarchie struct ifnet *ifp; /* associated interface */ 7362143Sarchie hook_p upper; /* upper hook connection */ 7462143Sarchie hook_p lower; /* lower OR orphan hook connection */ 7562143Sarchie u_char lowerOrphan; /* whether lower is lower or orphan */ 7662143Sarchie}; 7762143Sarchietypedef struct private *priv_p; 7862143Sarchie 7962143Sarchie/* Functional hooks called from if_ethersubr.c */ 8062143Sarchiestatic void ng_ether_input(struct ifnet *ifp, 8162143Sarchie struct mbuf **mp, struct ether_header *eh); 8262143Sarchiestatic void ng_ether_input_orphan(struct ifnet *ifp, 8362143Sarchie struct mbuf *m, struct ether_header *eh); 8462143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 8562143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 8662143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 8762143Sarchie 8862143Sarchie/* Other functions */ 8962143Sarchiestatic void ng_ether_input2(node_p node, 9062143Sarchie struct mbuf **mp, struct ether_header *eh); 9162143Sarchiestatic int ng_ether_glueback_header(struct mbuf **mp, 9262143Sarchie struct ether_header *eh); 9362143Sarchiestatic int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 9462143Sarchiestatic int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 9562143Sarchie 9662143Sarchie/* Netgraph node methods */ 9762143Sarchiestatic ng_constructor_t ng_ether_constructor; 9862143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 9962143Sarchiestatic ng_shutdown_t ng_ether_rmnode; 10062143Sarchiestatic ng_newhook_t ng_ether_newhook; 10162143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10262143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 10362143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 10462143Sarchie 10562143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 10662143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 10762143Sarchie { 10862143Sarchie NGM_ETHER_COOKIE, 10962143Sarchie NGM_ETHER_GET_IFNAME, 11062143Sarchie "getifname", 11162143Sarchie NULL, 11262143Sarchie &ng_parse_string_type 11362143Sarchie }, 11462143Sarchie { 11562143Sarchie NGM_ETHER_COOKIE, 11662143Sarchie NGM_ETHER_GET_IFINDEX, 11762143Sarchie "getifindex", 11862143Sarchie NULL, 11962143Sarchie &ng_parse_int32_type 12062143Sarchie }, 12162143Sarchie { 0 } 12262143Sarchie}; 12362143Sarchie 12462143Sarchiestatic struct ng_type ng_ether_typestruct = { 12562143Sarchie NG_VERSION, 12662143Sarchie NG_ETHER_NODE_TYPE, 12762143Sarchie ng_ether_mod_event, 12862143Sarchie ng_ether_constructor, 12962143Sarchie ng_ether_rcvmsg, 13062143Sarchie ng_ether_rmnode, 13162143Sarchie ng_ether_newhook, 13262143Sarchie NULL, 13362143Sarchie NULL, 13462143Sarchie ng_ether_rcvdata, 13562143Sarchie ng_ether_rcvdata, 13662143Sarchie ng_ether_disconnect, 13762143Sarchie ng_ether_cmdlist, 13862143Sarchie}; 13962143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 14062143Sarchie 14162143Sarchie/****************************************************************** 14262143Sarchie ETHERNET FUNCTION HOOKS 14362143Sarchie******************************************************************/ 14462143Sarchie 14562143Sarchie/* 14662143Sarchie * Handle a packet that has come in on an interface. We get to 14762143Sarchie * look at it here before any upper layer protocols do. 14862143Sarchie * 14962143Sarchie * NOTE: this function will get called at splimp() 15062143Sarchie */ 15162143Sarchiestatic void 15262143Sarchieng_ether_input(struct ifnet *ifp, 15362143Sarchie struct mbuf **mp, struct ether_header *eh) 15462143Sarchie{ 15562143Sarchie const node_p node = IFP2NG(ifp); 15662143Sarchie const priv_p priv = node->private; 15762143Sarchie 15862143Sarchie /* If "lower" hook not connected, let packet continue */ 15962143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 16062143Sarchie return; 16162143Sarchie ng_ether_input2(node, mp, eh); 16262143Sarchie} 16362143Sarchie 16462143Sarchie/* 16562143Sarchie * Handle a packet that has come in on an interface, and which 16662143Sarchie * does not match any of our known protocols (an ``orphan''). 16762143Sarchie * 16862143Sarchie * NOTE: this function will get called at splimp() 16962143Sarchie */ 17062143Sarchiestatic void 17162143Sarchieng_ether_input_orphan(struct ifnet *ifp, 17262143Sarchie struct mbuf *m, struct ether_header *eh) 17362143Sarchie{ 17462143Sarchie const node_p node = IFP2NG(ifp); 17562143Sarchie const priv_p priv = node->private; 17662143Sarchie 17762143Sarchie /* If "orphan" hook not connected, let packet continue */ 17862143Sarchie if (priv->lower == NULL || !priv->lowerOrphan) { 17962143Sarchie m_freem(m); 18062143Sarchie return; 18162143Sarchie } 18262143Sarchie ng_ether_input2(node, &m, eh); 18362143Sarchie if (m != NULL) 18462143Sarchie m_freem(m); 18562143Sarchie} 18662143Sarchie 18762143Sarchie/* 18862143Sarchie * Handle a packet that has come in on an interface. 18962143Sarchie * The Ethernet header has already been detached from the mbuf, 19062143Sarchie * so we have to put it back. 19162143Sarchie * 19262143Sarchie * NOTE: this function will get called at splimp() 19362143Sarchie */ 19462143Sarchiestatic void 19562143Sarchieng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh) 19662143Sarchie{ 19762143Sarchie const priv_p priv = node->private; 19862143Sarchie meta_p meta = NULL; 19962143Sarchie int error; 20062143Sarchie 20162143Sarchie /* Glue Ethernet header back on */ 20262143Sarchie if ((error = ng_ether_glueback_header(mp, eh)) != 0) 20362143Sarchie return; 20462143Sarchie 20562143Sarchie /* Send out lower/orphan hook */ 20663053Sarchie (void)ng_queue_data(priv->lower, *mp, meta); 20762143Sarchie *mp = NULL; 20862143Sarchie} 20962143Sarchie 21062143Sarchie/* 21162143Sarchie * Handle a packet that is going out on an interface. 21262143Sarchie * The Ethernet header is already attached to the mbuf. 21362143Sarchie */ 21462143Sarchiestatic int 21562143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 21662143Sarchie{ 21762143Sarchie const node_p node = IFP2NG(ifp); 21862143Sarchie const priv_p priv = node->private; 21962143Sarchie meta_p meta = NULL; 22062143Sarchie int error = 0; 22162143Sarchie 22262143Sarchie /* If "upper" hook not connected, let packet continue */ 22362143Sarchie if (priv->upper == NULL) 22462143Sarchie return (0); 22562143Sarchie 22662143Sarchie /* Send it out "upper" hook */ 22762143Sarchie NG_SEND_DATA_RET(error, priv->upper, *mp, meta); 22862143Sarchie 22962143Sarchie /* If we got a reflected packet back, handle it */ 23062143Sarchie if (error == 0 && *mp != NULL) { 23162143Sarchie error = ng_ether_rcv_upper(node, *mp, meta); 23262143Sarchie *mp = NULL; 23362143Sarchie } 23462143Sarchie return (error); 23562143Sarchie} 23662143Sarchie 23762143Sarchie/* 23862143Sarchie * A new Ethernet interface has been attached. 23962143Sarchie * Create a new node for it, etc. 24062143Sarchie */ 24162143Sarchiestatic void 24262143Sarchieng_ether_attach(struct ifnet *ifp) 24362143Sarchie{ 24462143Sarchie char name[IFNAMSIZ + 1]; 24562143Sarchie priv_p priv; 24662143Sarchie node_p node; 24762143Sarchie 24862143Sarchie /* Create node */ 24962143Sarchie KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__)); 25062143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 25162143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 25262143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 25362143Sarchie __FUNCTION__, "create node", name); 25462143Sarchie return; 25562143Sarchie } 25662143Sarchie 25762143Sarchie /* Allocate private data */ 25862143Sarchie MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT); 25962143Sarchie if (priv == NULL) { 26062143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 26162143Sarchie __FUNCTION__, "allocate memory", name); 26262143Sarchie ng_unref(node); 26362143Sarchie return; 26462143Sarchie } 26562143Sarchie bzero(priv, sizeof(*priv)); 26662143Sarchie node->private = priv; 26762143Sarchie priv->ifp = ifp; 26862143Sarchie IFP2NG(ifp) = node; 26962143Sarchie 27062143Sarchie /* Try to give the node the same name as the interface */ 27162143Sarchie if (ng_name_node(node, name) != 0) { 27262143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 27362143Sarchie __FUNCTION__, name); 27462143Sarchie } 27562143Sarchie} 27662143Sarchie 27762143Sarchie/* 27862143Sarchie * An Ethernet interface is being detached. 27962143Sarchie * Destroy its node. 28062143Sarchie */ 28162143Sarchiestatic void 28262143Sarchieng_ether_detach(struct ifnet *ifp) 28362143Sarchie{ 28462143Sarchie const node_p node = IFP2NG(ifp); 28562143Sarchie priv_p priv; 28662143Sarchie 28762143Sarchie if (node == NULL) /* no node (why not?), ignore */ 28862143Sarchie return; 28962143Sarchie ng_rmnode(node); /* break all links to other nodes */ 29062143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 29162143Sarchie priv = node->private; /* free node private info */ 29262143Sarchie bzero(priv, sizeof(*priv)); 29362143Sarchie FREE(priv, M_NETGRAPH); 29462143Sarchie node->private = NULL; 29562143Sarchie ng_unref(node); /* free node itself */ 29662143Sarchie} 29762143Sarchie 29862143Sarchie/* 29962143Sarchie * Optimization for gluing the Ethernet header back onto 30062143Sarchie * the front of an incoming packet. 30162143Sarchie */ 30262143Sarchiestatic int 30362143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 30462143Sarchie{ 30562143Sarchie struct mbuf *m = *mp; 30662143Sarchie uintfptr_t room; 30762143Sarchie int error = 0; 30862143Sarchie 30962143Sarchie /* 31062143Sarchie * Possibly the header is already on the front. 31162143Sarchie * If this is the case so just move the markers back 31262143Sarchie * to re-include it. We lucked out. 31362143Sarchie * This allows us to avoid a yucky m_pullup 31462143Sarchie * in later nodes if it works. 31562143Sarchie */ 31662143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 31762143Sarchie m->m_len += sizeof(*eh); 31862143Sarchie m->m_data -= sizeof(*eh); 31962143Sarchie m->m_pkthdr.len += sizeof(*eh); 32062143Sarchie goto done; 32162143Sarchie } 32262143Sarchie 32362143Sarchie /* 32462143Sarchie * Alternatively there may be room even though 32562143Sarchie * it is stored somewhere else. If so, copy it in. 32662143Sarchie * This only safe because we KNOW that this packet has 32762143Sarchie * just been generated by an ethernet card, so there are 32862143Sarchie * no aliases to the buffer (not so for outgoing packets). 32962143Sarchie * Nearly all ethernet cards will end up producing mbufs 33062143Sarchie * that fall into these cases. So we are not optimizing 33162143Sarchie * contorted cases. 33262143Sarchie */ 33362143Sarchie if ((m->m_flags & M_EXT) != 0) { 33462143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 33562143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 33662143Sarchie room = 0; 33762143Sarchie } else 33862143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 33962143Sarchie 34062143Sarchie /* 34162143Sarchie * If we have room, just copy it and adjust 34262143Sarchie */ 34362143Sarchie if (room >= sizeof(*eh)) { 34462143Sarchie m->m_len += sizeof(*eh); 34562143Sarchie m->m_data -= sizeof(*eh); 34662143Sarchie m->m_pkthdr.len += sizeof(*eh); 34762143Sarchie goto copy; 34862143Sarchie } 34962143Sarchie 35062143Sarchie /* 35162143Sarchie * Doing anything more is likely to get more 35262143Sarchie * expensive than it's worth.. 35362143Sarchie * it's probable that everything else is in one 35462143Sarchie * big lump. The next node will do an m_pullup() 35562143Sarchie * for exactly the amount of data it needs and 35662143Sarchie * hopefully everything after that will not 35762143Sarchie * need one. So let's just use M_PREPEND. 35862143Sarchie */ 35962143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 36062143Sarchie if (m == NULL) { 36162143Sarchie error = ENOBUFS; 36262143Sarchie goto done; 36362143Sarchie } 36462143Sarchie 36562143Sarchiecopy: 36662143Sarchie /* Copy header and return (possibly new) mbuf */ 36762143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 36862143Sarchiedone: 36962143Sarchie *mp = m; 37062143Sarchie return error; 37162143Sarchie} 37262143Sarchie 37362143Sarchie/****************************************************************** 37462143Sarchie NETGRAPH NODE METHODS 37562143Sarchie******************************************************************/ 37662143Sarchie 37762143Sarchie/* 37862143Sarchie * It is not possible or allowable to create a node of this type. 37962143Sarchie * Nodes get created when the interface is attached (or, when 38062143Sarchie * this node type's KLD is loaded). 38162143Sarchie */ 38262143Sarchiestatic int 38362143Sarchieng_ether_constructor(node_p *nodep) 38462143Sarchie{ 38562143Sarchie return (EINVAL); 38662143Sarchie} 38762143Sarchie 38862143Sarchie/* 38962143Sarchie * Check for attaching a new hook. 39062143Sarchie */ 39162143Sarchiestatic int 39262143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 39362143Sarchie{ 39462143Sarchie const priv_p priv = node->private; 39562143Sarchie u_char orphan = priv->lowerOrphan; 39662143Sarchie hook_p *hookptr; 39762143Sarchie 39862143Sarchie /* Divert hook is an alias for lower */ 39962143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 40062143Sarchie name = NG_ETHER_HOOK_LOWER; 40162143Sarchie 40262143Sarchie /* Which hook? */ 40362143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 40462143Sarchie hookptr = &priv->upper; 40562143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 40662143Sarchie hookptr = &priv->lower; 40762143Sarchie orphan = 0; 40862143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 40962143Sarchie hookptr = &priv->lower; 41062143Sarchie orphan = 1; 41162143Sarchie } else 41262143Sarchie return (EINVAL); 41362143Sarchie 41462143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 41562143Sarchie if (*hookptr != NULL) 41662143Sarchie return (EISCONN); 41762143Sarchie 41862143Sarchie /* OK */ 41962143Sarchie *hookptr = hook; 42062143Sarchie priv->lowerOrphan = orphan; 42162143Sarchie return (0); 42262143Sarchie} 42362143Sarchie 42462143Sarchie/* 42562143Sarchie * Receive an incoming control message. 42662143Sarchie */ 42762143Sarchiestatic int 42862143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 42962143Sarchie struct ng_mesg **rptr, hook_p lasthook) 43062143Sarchie{ 43162143Sarchie const priv_p priv = node->private; 43262143Sarchie struct ng_mesg *resp = NULL; 43362143Sarchie int error = 0; 43462143Sarchie 43562143Sarchie switch (msg->header.typecookie) { 43662143Sarchie case NGM_ETHER_COOKIE: 43762143Sarchie switch (msg->header.cmd) { 43862143Sarchie case NGM_ETHER_GET_IFNAME: 43962143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 44062143Sarchie if (resp == NULL) { 44162143Sarchie error = ENOMEM; 44262143Sarchie break; 44362143Sarchie } 44462143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 44562143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 44662143Sarchie break; 44762143Sarchie case NGM_ETHER_GET_IFINDEX: 44862143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 44962143Sarchie if (resp == NULL) { 45062143Sarchie error = ENOMEM; 45162143Sarchie break; 45262143Sarchie } 45362143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 45462143Sarchie break; 45562143Sarchie default: 45662143Sarchie error = EINVAL; 45762143Sarchie break; 45862143Sarchie } 45962143Sarchie break; 46062143Sarchie default: 46162143Sarchie error = EINVAL; 46262143Sarchie break; 46362143Sarchie } 46462143Sarchie if (rptr) 46562143Sarchie *rptr = resp; 46662143Sarchie else if (resp != NULL) 46762143Sarchie FREE(resp, M_NETGRAPH); 46862143Sarchie FREE(msg, M_NETGRAPH); 46962143Sarchie return (error); 47062143Sarchie} 47162143Sarchie 47262143Sarchie/* 47362143Sarchie * Receive data on a hook. 47462143Sarchie */ 47562143Sarchiestatic int 47662143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 47762143Sarchie struct mbuf **ret_m, meta_p *ret_meta) 47862143Sarchie{ 47962143Sarchie const node_p node = hook->node; 48062143Sarchie const priv_p priv = node->private; 48162143Sarchie 48262143Sarchie if (hook == priv->lower) 48362143Sarchie return ng_ether_rcv_lower(node, m, meta); 48462143Sarchie if (hook == priv->upper) 48562143Sarchie return ng_ether_rcv_upper(node, m, meta); 48662143Sarchie panic("%s: weird hook", __FUNCTION__); 48762143Sarchie} 48862143Sarchie 48962143Sarchie/* 49062143Sarchie * Handle an mbuf received on the "lower" hook. 49162143Sarchie */ 49262143Sarchiestatic int 49362143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 49462143Sarchie{ 49562143Sarchie const priv_p priv = node->private; 49662678Sjulian struct ether_header *eh; 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 50962678Sjulian /* drop in the MAC address */ 51062678Sjulian eh = mtod(m, struct ether_header *); 51162678Sjulian bcopy((IFP2AC(priv->ifp))->ac_enaddr, eh->ether_shost, 6); 51262678Sjulian 51362143Sarchie /* Send it on its way */ 51462143Sarchie NG_FREE_META(meta); 51562143Sarchie return ether_output_frame(priv->ifp, m); 51662143Sarchie} 51762143Sarchie 51862143Sarchie/* 51962143Sarchie * Handle an mbuf received on the "upper" hook. 52062143Sarchie */ 52162143Sarchiestatic int 52262143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 52362143Sarchie{ 52462143Sarchie const priv_p priv = node->private; 52562143Sarchie struct ether_header *eh; 52662143Sarchie 52762143Sarchie /* Check length and pull off header */ 52862143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 52962143Sarchie NG_FREE_DATA(m, meta); 53062143Sarchie return (EINVAL); 53162143Sarchie } 53262143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 53362143Sarchie NG_FREE_META(meta); 53462143Sarchie return (ENOBUFS); 53562143Sarchie } 53662143Sarchie eh = mtod(m, struct ether_header *); 53762143Sarchie m->m_data += sizeof(*eh); 53862143Sarchie m->m_len -= sizeof(*eh); 53962143Sarchie m->m_pkthdr.len -= sizeof(*eh); 54062143Sarchie 54162143Sarchie /* Route packet back in */ 54262143Sarchie NG_FREE_META(meta); 54362143Sarchie ether_demux(priv->ifp, eh, m); 54462143Sarchie return (0); 54562143Sarchie} 54662143Sarchie 54762143Sarchie/* 54862143Sarchie * Shutdown node. This resets the node but does not remove it. 54962143Sarchie */ 55062143Sarchiestatic int 55162143Sarchieng_ether_rmnode(node_p node) 55262143Sarchie{ 55362143Sarchie ng_cutlinks(node); 55462143Sarchie node->flags &= ~NG_INVALID; /* bounce back to life */ 55562143Sarchie return (0); 55662143Sarchie} 55762143Sarchie 55862143Sarchie/* 55962143Sarchie * Hook disconnection. 56062143Sarchie */ 56162143Sarchiestatic int 56262143Sarchieng_ether_disconnect(hook_p hook) 56362143Sarchie{ 56462143Sarchie const priv_p priv = hook->node->private; 56562143Sarchie 56662143Sarchie if (hook == priv->upper) 56762143Sarchie priv->upper = NULL; 56862143Sarchie else if (hook == priv->lower) { 56962143Sarchie priv->lower = NULL; 57062143Sarchie priv->lowerOrphan = 0; 57162143Sarchie } else 57262143Sarchie panic("%s: weird hook", __FUNCTION__); 57362143Sarchie return (0); 57462143Sarchie} 57562143Sarchie 57662143Sarchie/****************************************************************** 57762143Sarchie INITIALIZATION 57862143Sarchie******************************************************************/ 57962143Sarchie 58062143Sarchie/* 58162143Sarchie * Handle loading and unloading for this node type. 58262143Sarchie */ 58362143Sarchiestatic int 58462143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 58562143Sarchie{ 58662143Sarchie struct ifnet *ifp; 58762143Sarchie int error = 0; 58862143Sarchie int s; 58962143Sarchie 59062143Sarchie s = splnet(); 59162143Sarchie switch (event) { 59262143Sarchie case MOD_LOAD: 59362143Sarchie 59462143Sarchie /* Register function hooks */ 59562143Sarchie if (ng_ether_attach_p != NULL) { 59662143Sarchie error = EEXIST; 59762143Sarchie break; 59862143Sarchie } 59962143Sarchie ng_ether_attach_p = ng_ether_attach; 60062143Sarchie ng_ether_detach_p = ng_ether_detach; 60162143Sarchie ng_ether_output_p = ng_ether_output; 60262143Sarchie ng_ether_input_p = ng_ether_input; 60362143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 60462143Sarchie 60562143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 60662143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 60762143Sarchie if (ifp->if_type == IFT_ETHER) 60862143Sarchie ng_ether_attach(ifp); 60962143Sarchie } 61062143Sarchie break; 61162143Sarchie 61262143Sarchie case MOD_UNLOAD: 61362143Sarchie 61462143Sarchie /* 61562143Sarchie * Note that the base code won't try to unload us until 61662143Sarchie * all nodes have been removed, and that can't happen 61762143Sarchie * until all Ethernet interfaces are removed. In any 61862143Sarchie * case, we know there are no nodes left if the action 61962143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 62062143Sarchie */ 62162143Sarchie 62262143Sarchie /* Unregister function hooks */ 62362143Sarchie ng_ether_attach_p = NULL; 62462143Sarchie ng_ether_detach_p = NULL; 62562143Sarchie ng_ether_output_p = NULL; 62662143Sarchie ng_ether_input_p = NULL; 62762143Sarchie ng_ether_input_orphan_p = NULL; 62862143Sarchie break; 62962143Sarchie 63062143Sarchie default: 63162143Sarchie error = EOPNOTSUPP; 63262143Sarchie break; 63362143Sarchie } 63462143Sarchie splx(s); 63562143Sarchie return (error); 63662143Sarchie} 63762143Sarchie 638