ng_ether.c revision 63543
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 63543 2000-07-19 17:33:53Z 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 */ 29063195Sarchie node->flags |= NG_INVALID; 29163543Sarchie ng_unname(node); /* free name (and its reference) */ 29262143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 29362143Sarchie priv = node->private; /* free node private info */ 29462143Sarchie bzero(priv, sizeof(*priv)); 29562143Sarchie FREE(priv, M_NETGRAPH); 29662143Sarchie node->private = NULL; 29762143Sarchie ng_unref(node); /* free node itself */ 29862143Sarchie} 29962143Sarchie 30062143Sarchie/* 30162143Sarchie * Optimization for gluing the Ethernet header back onto 30262143Sarchie * the front of an incoming packet. 30362143Sarchie */ 30462143Sarchiestatic int 30562143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 30662143Sarchie{ 30762143Sarchie struct mbuf *m = *mp; 30862143Sarchie uintfptr_t room; 30962143Sarchie int error = 0; 31062143Sarchie 31162143Sarchie /* 31262143Sarchie * Possibly the header is already on the front. 31362143Sarchie * If this is the case so just move the markers back 31462143Sarchie * to re-include it. We lucked out. 31562143Sarchie * This allows us to avoid a yucky m_pullup 31662143Sarchie * in later nodes if it works. 31762143Sarchie */ 31862143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 31962143Sarchie m->m_len += sizeof(*eh); 32062143Sarchie m->m_data -= sizeof(*eh); 32162143Sarchie m->m_pkthdr.len += sizeof(*eh); 32262143Sarchie goto done; 32362143Sarchie } 32462143Sarchie 32562143Sarchie /* 32662143Sarchie * Alternatively there may be room even though 32762143Sarchie * it is stored somewhere else. If so, copy it in. 32862143Sarchie * This only safe because we KNOW that this packet has 32962143Sarchie * just been generated by an ethernet card, so there are 33062143Sarchie * no aliases to the buffer (not so for outgoing packets). 33162143Sarchie * Nearly all ethernet cards will end up producing mbufs 33262143Sarchie * that fall into these cases. So we are not optimizing 33362143Sarchie * contorted cases. 33462143Sarchie */ 33562143Sarchie if ((m->m_flags & M_EXT) != 0) { 33662143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 33762143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 33862143Sarchie room = 0; 33962143Sarchie } else 34062143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 34162143Sarchie 34262143Sarchie /* 34362143Sarchie * If we have room, just copy it and adjust 34462143Sarchie */ 34562143Sarchie if (room >= sizeof(*eh)) { 34662143Sarchie m->m_len += sizeof(*eh); 34762143Sarchie m->m_data -= sizeof(*eh); 34862143Sarchie m->m_pkthdr.len += sizeof(*eh); 34962143Sarchie goto copy; 35062143Sarchie } 35162143Sarchie 35262143Sarchie /* 35362143Sarchie * Doing anything more is likely to get more 35462143Sarchie * expensive than it's worth.. 35562143Sarchie * it's probable that everything else is in one 35662143Sarchie * big lump. The next node will do an m_pullup() 35762143Sarchie * for exactly the amount of data it needs and 35862143Sarchie * hopefully everything after that will not 35962143Sarchie * need one. So let's just use M_PREPEND. 36062143Sarchie */ 36162143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 36262143Sarchie if (m == NULL) { 36362143Sarchie error = ENOBUFS; 36462143Sarchie goto done; 36562143Sarchie } 36662143Sarchie 36762143Sarchiecopy: 36862143Sarchie /* Copy header and return (possibly new) mbuf */ 36962143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 37062143Sarchiedone: 37162143Sarchie *mp = m; 37262143Sarchie return error; 37362143Sarchie} 37462143Sarchie 37562143Sarchie/****************************************************************** 37662143Sarchie NETGRAPH NODE METHODS 37762143Sarchie******************************************************************/ 37862143Sarchie 37962143Sarchie/* 38062143Sarchie * It is not possible or allowable to create a node of this type. 38162143Sarchie * Nodes get created when the interface is attached (or, when 38262143Sarchie * this node type's KLD is loaded). 38362143Sarchie */ 38462143Sarchiestatic int 38562143Sarchieng_ether_constructor(node_p *nodep) 38662143Sarchie{ 38762143Sarchie return (EINVAL); 38862143Sarchie} 38962143Sarchie 39062143Sarchie/* 39162143Sarchie * Check for attaching a new hook. 39262143Sarchie */ 39362143Sarchiestatic int 39462143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 39562143Sarchie{ 39662143Sarchie const priv_p priv = node->private; 39762143Sarchie u_char orphan = priv->lowerOrphan; 39862143Sarchie hook_p *hookptr; 39962143Sarchie 40062143Sarchie /* Divert hook is an alias for lower */ 40162143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 40262143Sarchie name = NG_ETHER_HOOK_LOWER; 40362143Sarchie 40462143Sarchie /* Which hook? */ 40562143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 40662143Sarchie hookptr = &priv->upper; 40762143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 40862143Sarchie hookptr = &priv->lower; 40962143Sarchie orphan = 0; 41062143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 41162143Sarchie hookptr = &priv->lower; 41262143Sarchie orphan = 1; 41362143Sarchie } else 41462143Sarchie return (EINVAL); 41562143Sarchie 41662143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 41762143Sarchie if (*hookptr != NULL) 41862143Sarchie return (EISCONN); 41962143Sarchie 42062143Sarchie /* OK */ 42162143Sarchie *hookptr = hook; 42262143Sarchie priv->lowerOrphan = orphan; 42362143Sarchie return (0); 42462143Sarchie} 42562143Sarchie 42662143Sarchie/* 42762143Sarchie * Receive an incoming control message. 42862143Sarchie */ 42962143Sarchiestatic int 43062143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 43162143Sarchie struct ng_mesg **rptr, hook_p lasthook) 43262143Sarchie{ 43362143Sarchie const priv_p priv = node->private; 43462143Sarchie struct ng_mesg *resp = NULL; 43562143Sarchie int error = 0; 43662143Sarchie 43762143Sarchie switch (msg->header.typecookie) { 43862143Sarchie case NGM_ETHER_COOKIE: 43962143Sarchie switch (msg->header.cmd) { 44062143Sarchie case NGM_ETHER_GET_IFNAME: 44162143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 44262143Sarchie if (resp == NULL) { 44362143Sarchie error = ENOMEM; 44462143Sarchie break; 44562143Sarchie } 44662143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 44762143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 44862143Sarchie break; 44962143Sarchie case NGM_ETHER_GET_IFINDEX: 45062143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 45162143Sarchie if (resp == NULL) { 45262143Sarchie error = ENOMEM; 45362143Sarchie break; 45462143Sarchie } 45562143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 45662143Sarchie break; 45762143Sarchie default: 45862143Sarchie error = EINVAL; 45962143Sarchie break; 46062143Sarchie } 46162143Sarchie break; 46262143Sarchie default: 46362143Sarchie error = EINVAL; 46462143Sarchie break; 46562143Sarchie } 46662143Sarchie if (rptr) 46762143Sarchie *rptr = resp; 46862143Sarchie else if (resp != NULL) 46962143Sarchie FREE(resp, M_NETGRAPH); 47062143Sarchie FREE(msg, M_NETGRAPH); 47162143Sarchie return (error); 47262143Sarchie} 47362143Sarchie 47462143Sarchie/* 47562143Sarchie * Receive data on a hook. 47662143Sarchie */ 47762143Sarchiestatic int 47862143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 47962143Sarchie struct mbuf **ret_m, meta_p *ret_meta) 48062143Sarchie{ 48162143Sarchie const node_p node = hook->node; 48262143Sarchie const priv_p priv = node->private; 48362143Sarchie 48462143Sarchie if (hook == priv->lower) 48562143Sarchie return ng_ether_rcv_lower(node, m, meta); 48662143Sarchie if (hook == priv->upper) 48762143Sarchie return ng_ether_rcv_upper(node, m, meta); 48862143Sarchie panic("%s: weird hook", __FUNCTION__); 48962143Sarchie} 49062143Sarchie 49162143Sarchie/* 49262143Sarchie * Handle an mbuf received on the "lower" hook. 49362143Sarchie */ 49462143Sarchiestatic int 49562143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 49662143Sarchie{ 49762143Sarchie const priv_p priv = node->private; 49862678Sjulian struct ether_header *eh; 49962143Sarchie 50062143Sarchie /* Make sure header is fully pulled up */ 50162143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 50262143Sarchie NG_FREE_DATA(m, meta); 50362143Sarchie return (EINVAL); 50462143Sarchie } 50562143Sarchie if (m->m_len < sizeof(struct ether_header) 50662143Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 50762143Sarchie NG_FREE_META(meta); 50862143Sarchie return (ENOBUFS); 50962143Sarchie } 51062143Sarchie 51162678Sjulian /* drop in the MAC address */ 51262678Sjulian eh = mtod(m, struct ether_header *); 51362678Sjulian bcopy((IFP2AC(priv->ifp))->ac_enaddr, eh->ether_shost, 6); 51462678Sjulian 51562143Sarchie /* Send it on its way */ 51662143Sarchie NG_FREE_META(meta); 51762143Sarchie return ether_output_frame(priv->ifp, m); 51862143Sarchie} 51962143Sarchie 52062143Sarchie/* 52162143Sarchie * Handle an mbuf received on the "upper" hook. 52262143Sarchie */ 52362143Sarchiestatic int 52462143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 52562143Sarchie{ 52662143Sarchie const priv_p priv = node->private; 52762143Sarchie struct ether_header *eh; 52862143Sarchie 52962143Sarchie /* Check length and pull off header */ 53062143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 53162143Sarchie NG_FREE_DATA(m, meta); 53262143Sarchie return (EINVAL); 53362143Sarchie } 53462143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 53562143Sarchie NG_FREE_META(meta); 53662143Sarchie return (ENOBUFS); 53762143Sarchie } 53862143Sarchie eh = mtod(m, struct ether_header *); 53962143Sarchie m->m_data += sizeof(*eh); 54062143Sarchie m->m_len -= sizeof(*eh); 54162143Sarchie m->m_pkthdr.len -= sizeof(*eh); 54262143Sarchie 54362143Sarchie /* Route packet back in */ 54462143Sarchie NG_FREE_META(meta); 54562143Sarchie ether_demux(priv->ifp, eh, m); 54662143Sarchie return (0); 54762143Sarchie} 54862143Sarchie 54962143Sarchie/* 55062143Sarchie * Shutdown node. This resets the node but does not remove it. 55162143Sarchie */ 55262143Sarchiestatic int 55362143Sarchieng_ether_rmnode(node_p node) 55462143Sarchie{ 55562143Sarchie ng_cutlinks(node); 55662143Sarchie node->flags &= ~NG_INVALID; /* bounce back to life */ 55762143Sarchie return (0); 55862143Sarchie} 55962143Sarchie 56062143Sarchie/* 56162143Sarchie * Hook disconnection. 56262143Sarchie */ 56362143Sarchiestatic int 56462143Sarchieng_ether_disconnect(hook_p hook) 56562143Sarchie{ 56662143Sarchie const priv_p priv = hook->node->private; 56762143Sarchie 56862143Sarchie if (hook == priv->upper) 56962143Sarchie priv->upper = NULL; 57062143Sarchie else if (hook == priv->lower) { 57162143Sarchie priv->lower = NULL; 57262143Sarchie priv->lowerOrphan = 0; 57362143Sarchie } else 57462143Sarchie panic("%s: weird hook", __FUNCTION__); 57562143Sarchie return (0); 57662143Sarchie} 57762143Sarchie 57862143Sarchie/****************************************************************** 57962143Sarchie INITIALIZATION 58062143Sarchie******************************************************************/ 58162143Sarchie 58262143Sarchie/* 58362143Sarchie * Handle loading and unloading for this node type. 58462143Sarchie */ 58562143Sarchiestatic int 58662143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 58762143Sarchie{ 58862143Sarchie struct ifnet *ifp; 58962143Sarchie int error = 0; 59062143Sarchie int s; 59162143Sarchie 59262143Sarchie s = splnet(); 59362143Sarchie switch (event) { 59462143Sarchie case MOD_LOAD: 59562143Sarchie 59662143Sarchie /* Register function hooks */ 59762143Sarchie if (ng_ether_attach_p != NULL) { 59862143Sarchie error = EEXIST; 59962143Sarchie break; 60062143Sarchie } 60162143Sarchie ng_ether_attach_p = ng_ether_attach; 60262143Sarchie ng_ether_detach_p = ng_ether_detach; 60362143Sarchie ng_ether_output_p = ng_ether_output; 60462143Sarchie ng_ether_input_p = ng_ether_input; 60562143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 60662143Sarchie 60762143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 60862143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 60962143Sarchie if (ifp->if_type == IFT_ETHER) 61062143Sarchie ng_ether_attach(ifp); 61162143Sarchie } 61262143Sarchie break; 61362143Sarchie 61462143Sarchie case MOD_UNLOAD: 61562143Sarchie 61662143Sarchie /* 61762143Sarchie * Note that the base code won't try to unload us until 61862143Sarchie * all nodes have been removed, and that can't happen 61962143Sarchie * until all Ethernet interfaces are removed. In any 62062143Sarchie * case, we know there are no nodes left if the action 62162143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 62262143Sarchie */ 62362143Sarchie 62462143Sarchie /* Unregister function hooks */ 62562143Sarchie ng_ether_attach_p = NULL; 62662143Sarchie ng_ether_detach_p = NULL; 62762143Sarchie ng_ether_output_p = NULL; 62862143Sarchie ng_ether_input_p = NULL; 62962143Sarchie ng_ether_input_orphan_p = NULL; 63062143Sarchie break; 63162143Sarchie 63262143Sarchie default: 63362143Sarchie error = EOPNOTSUPP; 63462143Sarchie break; 63562143Sarchie } 63662143Sarchie splx(s); 63762143Sarchie return (error); 63862143Sarchie} 63962143Sarchie 640