ng_ether.c revision 64653
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 64653 2000-08-15 01:05:50Z 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 */ 7664358Sarchie u_char autoSrcAddr; /* always overwrite source address */ 7764358Sarchie u_char promisc; /* promiscuous mode enabled */ 7862143Sarchie}; 7962143Sarchietypedef struct private *priv_p; 8062143Sarchie 8162143Sarchie/* Functional hooks called from if_ethersubr.c */ 8262143Sarchiestatic void ng_ether_input(struct ifnet *ifp, 8362143Sarchie struct mbuf **mp, struct ether_header *eh); 8462143Sarchiestatic void ng_ether_input_orphan(struct ifnet *ifp, 8562143Sarchie struct mbuf *m, struct ether_header *eh); 8662143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 8762143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 8862143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 8962143Sarchie 9062143Sarchie/* Other functions */ 9162143Sarchiestatic void ng_ether_input2(node_p node, 9262143Sarchie struct mbuf **mp, struct ether_header *eh); 9362143Sarchiestatic int ng_ether_glueback_header(struct mbuf **mp, 9462143Sarchie struct ether_header *eh); 9562143Sarchiestatic int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 9662143Sarchiestatic int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 9762143Sarchie 9862143Sarchie/* Netgraph node methods */ 9962143Sarchiestatic ng_constructor_t ng_ether_constructor; 10062143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 10162143Sarchiestatic ng_shutdown_t ng_ether_rmnode; 10262143Sarchiestatic ng_newhook_t ng_ether_newhook; 10362143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10462143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 10562143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 10662143Sarchie 10764653Sarchie/* Parse type for an Ethernet address */ 10864653Sarchiestatic ng_parse_t ng_enaddr_parse; 10964653Sarchiestatic ng_unparse_t ng_enaddr_unparse; 11064653Sarchieconst struct ng_parse_type ng_ether_enaddr_type = { 11164653Sarchie NULL, 11264653Sarchie NULL, 11364653Sarchie NULL, 11464653Sarchie ng_enaddr_parse, 11564653Sarchie ng_enaddr_unparse, 11664653Sarchie NULL, /* no such thing as a "default" EN address */ 11764653Sarchie 0 11864358Sarchie}; 11964358Sarchie 12062143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12162143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 12262143Sarchie { 12362143Sarchie NGM_ETHER_COOKIE, 12462143Sarchie NGM_ETHER_GET_IFNAME, 12562143Sarchie "getifname", 12662143Sarchie NULL, 12762143Sarchie &ng_parse_string_type 12862143Sarchie }, 12962143Sarchie { 13062143Sarchie NGM_ETHER_COOKIE, 13162143Sarchie NGM_ETHER_GET_IFINDEX, 13262143Sarchie "getifindex", 13362143Sarchie NULL, 13462143Sarchie &ng_parse_int32_type 13562143Sarchie }, 13664358Sarchie { 13764358Sarchie NGM_ETHER_COOKIE, 13864358Sarchie NGM_ETHER_GET_ENADDR, 13964358Sarchie "getenaddr", 14064358Sarchie NULL, 14164358Sarchie &ng_ether_enaddr_type 14264358Sarchie }, 14364358Sarchie { 14464358Sarchie NGM_ETHER_COOKIE, 14564653Sarchie NGM_ETHER_SET_ENADDR, 14664653Sarchie "setenaddr", 14764653Sarchie &ng_ether_enaddr_type, 14864653Sarchie NULL 14964653Sarchie }, 15064653Sarchie { 15164653Sarchie NGM_ETHER_COOKIE, 15264653Sarchie NGM_ETHER_GET_PROMISC, 15364653Sarchie "getpromisc", 15464653Sarchie NULL, 15564653Sarchie &ng_parse_int32_type 15664653Sarchie }, 15764653Sarchie { 15864653Sarchie NGM_ETHER_COOKIE, 15964358Sarchie NGM_ETHER_SET_PROMISC, 16064358Sarchie "setpromisc", 16164358Sarchie &ng_parse_int32_type, 16264358Sarchie NULL 16364358Sarchie }, 16464358Sarchie { 16564358Sarchie NGM_ETHER_COOKIE, 16664653Sarchie NGM_ETHER_GET_AUTOSRC, 16764653Sarchie "getautosrc", 16864653Sarchie NULL, 16964653Sarchie &ng_parse_int32_type 17064653Sarchie }, 17164653Sarchie { 17264653Sarchie NGM_ETHER_COOKIE, 17364358Sarchie NGM_ETHER_SET_AUTOSRC, 17464358Sarchie "setautosrc", 17564358Sarchie &ng_parse_int32_type, 17664358Sarchie NULL 17764358Sarchie }, 17862143Sarchie { 0 } 17962143Sarchie}; 18062143Sarchie 18162143Sarchiestatic struct ng_type ng_ether_typestruct = { 18262143Sarchie NG_VERSION, 18362143Sarchie NG_ETHER_NODE_TYPE, 18462143Sarchie ng_ether_mod_event, 18562143Sarchie ng_ether_constructor, 18662143Sarchie ng_ether_rcvmsg, 18762143Sarchie ng_ether_rmnode, 18862143Sarchie ng_ether_newhook, 18962143Sarchie NULL, 19062143Sarchie NULL, 19162143Sarchie ng_ether_rcvdata, 19262143Sarchie ng_ether_rcvdata, 19362143Sarchie ng_ether_disconnect, 19462143Sarchie ng_ether_cmdlist, 19562143Sarchie}; 19662143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 19762143Sarchie 19862143Sarchie/****************************************************************** 19962143Sarchie ETHERNET FUNCTION HOOKS 20062143Sarchie******************************************************************/ 20162143Sarchie 20262143Sarchie/* 20362143Sarchie * Handle a packet that has come in on an interface. We get to 20462143Sarchie * look at it here before any upper layer protocols do. 20562143Sarchie * 20662143Sarchie * NOTE: this function will get called at splimp() 20762143Sarchie */ 20862143Sarchiestatic void 20962143Sarchieng_ether_input(struct ifnet *ifp, 21062143Sarchie struct mbuf **mp, struct ether_header *eh) 21162143Sarchie{ 21262143Sarchie const node_p node = IFP2NG(ifp); 21362143Sarchie const priv_p priv = node->private; 21462143Sarchie 21562143Sarchie /* If "lower" hook not connected, let packet continue */ 21662143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 21762143Sarchie return; 21862143Sarchie ng_ether_input2(node, mp, eh); 21962143Sarchie} 22062143Sarchie 22162143Sarchie/* 22262143Sarchie * Handle a packet that has come in on an interface, and which 22362143Sarchie * does not match any of our known protocols (an ``orphan''). 22462143Sarchie * 22562143Sarchie * NOTE: this function will get called at splimp() 22662143Sarchie */ 22762143Sarchiestatic void 22862143Sarchieng_ether_input_orphan(struct ifnet *ifp, 22962143Sarchie struct mbuf *m, struct ether_header *eh) 23062143Sarchie{ 23162143Sarchie const node_p node = IFP2NG(ifp); 23262143Sarchie const priv_p priv = node->private; 23362143Sarchie 23462143Sarchie /* If "orphan" hook not connected, let packet continue */ 23562143Sarchie if (priv->lower == NULL || !priv->lowerOrphan) { 23662143Sarchie m_freem(m); 23762143Sarchie return; 23862143Sarchie } 23962143Sarchie ng_ether_input2(node, &m, eh); 24062143Sarchie if (m != NULL) 24162143Sarchie m_freem(m); 24262143Sarchie} 24362143Sarchie 24462143Sarchie/* 24562143Sarchie * Handle a packet that has come in on an interface. 24662143Sarchie * The Ethernet header has already been detached from the mbuf, 24762143Sarchie * so we have to put it back. 24862143Sarchie * 24962143Sarchie * NOTE: this function will get called at splimp() 25062143Sarchie */ 25162143Sarchiestatic void 25262143Sarchieng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh) 25362143Sarchie{ 25462143Sarchie const priv_p priv = node->private; 25562143Sarchie meta_p meta = NULL; 25662143Sarchie int error; 25762143Sarchie 25862143Sarchie /* Glue Ethernet header back on */ 25962143Sarchie if ((error = ng_ether_glueback_header(mp, eh)) != 0) 26062143Sarchie return; 26162143Sarchie 26262143Sarchie /* Send out lower/orphan hook */ 26363053Sarchie (void)ng_queue_data(priv->lower, *mp, meta); 26462143Sarchie *mp = NULL; 26562143Sarchie} 26662143Sarchie 26762143Sarchie/* 26862143Sarchie * Handle a packet that is going out on an interface. 26962143Sarchie * The Ethernet header is already attached to the mbuf. 27062143Sarchie */ 27162143Sarchiestatic int 27262143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 27362143Sarchie{ 27462143Sarchie const node_p node = IFP2NG(ifp); 27562143Sarchie const priv_p priv = node->private; 27662143Sarchie meta_p meta = NULL; 27762143Sarchie int error = 0; 27862143Sarchie 27962143Sarchie /* If "upper" hook not connected, let packet continue */ 28062143Sarchie if (priv->upper == NULL) 28162143Sarchie return (0); 28262143Sarchie 28362143Sarchie /* Send it out "upper" hook */ 28462143Sarchie NG_SEND_DATA_RET(error, priv->upper, *mp, meta); 28562143Sarchie 28662143Sarchie /* If we got a reflected packet back, handle it */ 28762143Sarchie if (error == 0 && *mp != NULL) { 28862143Sarchie error = ng_ether_rcv_upper(node, *mp, meta); 28962143Sarchie *mp = NULL; 29062143Sarchie } 29162143Sarchie return (error); 29262143Sarchie} 29362143Sarchie 29462143Sarchie/* 29562143Sarchie * A new Ethernet interface has been attached. 29662143Sarchie * Create a new node for it, etc. 29762143Sarchie */ 29862143Sarchiestatic void 29962143Sarchieng_ether_attach(struct ifnet *ifp) 30062143Sarchie{ 30162143Sarchie char name[IFNAMSIZ + 1]; 30262143Sarchie priv_p priv; 30362143Sarchie node_p node; 30462143Sarchie 30562143Sarchie /* Create node */ 30662143Sarchie KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__)); 30762143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 30862143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 30962143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 31062143Sarchie __FUNCTION__, "create node", name); 31162143Sarchie return; 31262143Sarchie } 31362143Sarchie 31462143Sarchie /* Allocate private data */ 31562143Sarchie MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT); 31662143Sarchie if (priv == NULL) { 31762143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 31862143Sarchie __FUNCTION__, "allocate memory", name); 31962143Sarchie ng_unref(node); 32062143Sarchie return; 32162143Sarchie } 32262143Sarchie bzero(priv, sizeof(*priv)); 32362143Sarchie node->private = priv; 32462143Sarchie priv->ifp = ifp; 32562143Sarchie IFP2NG(ifp) = node; 32664358Sarchie priv->autoSrcAddr = 1; 32762143Sarchie 32862143Sarchie /* Try to give the node the same name as the interface */ 32962143Sarchie if (ng_name_node(node, name) != 0) { 33062143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 33162143Sarchie __FUNCTION__, name); 33262143Sarchie } 33362143Sarchie} 33462143Sarchie 33562143Sarchie/* 33662143Sarchie * An Ethernet interface is being detached. 33762143Sarchie * Destroy its node. 33862143Sarchie */ 33962143Sarchiestatic void 34062143Sarchieng_ether_detach(struct ifnet *ifp) 34162143Sarchie{ 34262143Sarchie const node_p node = IFP2NG(ifp); 34362143Sarchie priv_p priv; 34462143Sarchie 34562143Sarchie if (node == NULL) /* no node (why not?), ignore */ 34662143Sarchie return; 34762143Sarchie ng_rmnode(node); /* break all links to other nodes */ 34863195Sarchie node->flags |= NG_INVALID; 34963543Sarchie ng_unname(node); /* free name (and its reference) */ 35062143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 35162143Sarchie priv = node->private; /* free node private info */ 35262143Sarchie bzero(priv, sizeof(*priv)); 35362143Sarchie FREE(priv, M_NETGRAPH); 35462143Sarchie node->private = NULL; 35562143Sarchie ng_unref(node); /* free node itself */ 35662143Sarchie} 35762143Sarchie 35862143Sarchie/* 35962143Sarchie * Optimization for gluing the Ethernet header back onto 36062143Sarchie * the front of an incoming packet. 36162143Sarchie */ 36262143Sarchiestatic int 36362143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 36462143Sarchie{ 36562143Sarchie struct mbuf *m = *mp; 36662143Sarchie uintfptr_t room; 36762143Sarchie int error = 0; 36862143Sarchie 36962143Sarchie /* 37062143Sarchie * Possibly the header is already on the front. 37162143Sarchie * If this is the case so just move the markers back 37262143Sarchie * to re-include it. We lucked out. 37362143Sarchie * This allows us to avoid a yucky m_pullup 37462143Sarchie * in later nodes if it works. 37562143Sarchie */ 37662143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 37762143Sarchie m->m_len += sizeof(*eh); 37862143Sarchie m->m_data -= sizeof(*eh); 37962143Sarchie m->m_pkthdr.len += sizeof(*eh); 38062143Sarchie goto done; 38162143Sarchie } 38262143Sarchie 38362143Sarchie /* 38462143Sarchie * Alternatively there may be room even though 38562143Sarchie * it is stored somewhere else. If so, copy it in. 38662143Sarchie * This only safe because we KNOW that this packet has 38762143Sarchie * just been generated by an ethernet card, so there are 38862143Sarchie * no aliases to the buffer (not so for outgoing packets). 38962143Sarchie * Nearly all ethernet cards will end up producing mbufs 39062143Sarchie * that fall into these cases. So we are not optimizing 39162143Sarchie * contorted cases. 39262143Sarchie */ 39362143Sarchie if ((m->m_flags & M_EXT) != 0) { 39462143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 39562143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 39662143Sarchie room = 0; 39762143Sarchie } else 39862143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 39962143Sarchie 40062143Sarchie /* 40162143Sarchie * If we have room, just copy it and adjust 40262143Sarchie */ 40362143Sarchie if (room >= sizeof(*eh)) { 40462143Sarchie m->m_len += sizeof(*eh); 40562143Sarchie m->m_data -= sizeof(*eh); 40662143Sarchie m->m_pkthdr.len += sizeof(*eh); 40762143Sarchie goto copy; 40862143Sarchie } 40962143Sarchie 41062143Sarchie /* 41162143Sarchie * Doing anything more is likely to get more 41262143Sarchie * expensive than it's worth.. 41362143Sarchie * it's probable that everything else is in one 41462143Sarchie * big lump. The next node will do an m_pullup() 41562143Sarchie * for exactly the amount of data it needs and 41662143Sarchie * hopefully everything after that will not 41762143Sarchie * need one. So let's just use M_PREPEND. 41862143Sarchie */ 41962143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 42062143Sarchie if (m == NULL) { 42162143Sarchie error = ENOBUFS; 42262143Sarchie goto done; 42362143Sarchie } 42462143Sarchie 42562143Sarchiecopy: 42662143Sarchie /* Copy header and return (possibly new) mbuf */ 42762143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 42862143Sarchiedone: 42962143Sarchie *mp = m; 43062143Sarchie return error; 43162143Sarchie} 43262143Sarchie 43362143Sarchie/****************************************************************** 43462143Sarchie NETGRAPH NODE METHODS 43562143Sarchie******************************************************************/ 43662143Sarchie 43762143Sarchie/* 43862143Sarchie * It is not possible or allowable to create a node of this type. 43962143Sarchie * Nodes get created when the interface is attached (or, when 44062143Sarchie * this node type's KLD is loaded). 44162143Sarchie */ 44262143Sarchiestatic int 44362143Sarchieng_ether_constructor(node_p *nodep) 44462143Sarchie{ 44562143Sarchie return (EINVAL); 44662143Sarchie} 44762143Sarchie 44862143Sarchie/* 44962143Sarchie * Check for attaching a new hook. 45062143Sarchie */ 45162143Sarchiestatic int 45262143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 45362143Sarchie{ 45462143Sarchie const priv_p priv = node->private; 45562143Sarchie u_char orphan = priv->lowerOrphan; 45662143Sarchie hook_p *hookptr; 45762143Sarchie 45862143Sarchie /* Divert hook is an alias for lower */ 45962143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 46062143Sarchie name = NG_ETHER_HOOK_LOWER; 46162143Sarchie 46262143Sarchie /* Which hook? */ 46362143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 46462143Sarchie hookptr = &priv->upper; 46562143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 46662143Sarchie hookptr = &priv->lower; 46762143Sarchie orphan = 0; 46862143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 46962143Sarchie hookptr = &priv->lower; 47062143Sarchie orphan = 1; 47162143Sarchie } else 47262143Sarchie return (EINVAL); 47362143Sarchie 47462143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 47562143Sarchie if (*hookptr != NULL) 47662143Sarchie return (EISCONN); 47762143Sarchie 47862143Sarchie /* OK */ 47962143Sarchie *hookptr = hook; 48062143Sarchie priv->lowerOrphan = orphan; 48162143Sarchie return (0); 48262143Sarchie} 48362143Sarchie 48462143Sarchie/* 48562143Sarchie * Receive an incoming control message. 48662143Sarchie */ 48762143Sarchiestatic int 48862143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 48962143Sarchie struct ng_mesg **rptr, hook_p lasthook) 49062143Sarchie{ 49162143Sarchie const priv_p priv = node->private; 49262143Sarchie struct ng_mesg *resp = NULL; 49362143Sarchie int error = 0; 49462143Sarchie 49562143Sarchie switch (msg->header.typecookie) { 49662143Sarchie case NGM_ETHER_COOKIE: 49762143Sarchie switch (msg->header.cmd) { 49862143Sarchie case NGM_ETHER_GET_IFNAME: 49962143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 50062143Sarchie if (resp == NULL) { 50162143Sarchie error = ENOMEM; 50262143Sarchie break; 50362143Sarchie } 50462143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 50562143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 50662143Sarchie break; 50762143Sarchie case NGM_ETHER_GET_IFINDEX: 50862143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 50962143Sarchie if (resp == NULL) { 51062143Sarchie error = ENOMEM; 51162143Sarchie break; 51262143Sarchie } 51362143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 51462143Sarchie break; 51564358Sarchie case NGM_ETHER_GET_ENADDR: 51664358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 51764358Sarchie if (resp == NULL) { 51864358Sarchie error = ENOMEM; 51964358Sarchie break; 52064358Sarchie } 52164358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 52264358Sarchie resp->data, ETHER_ADDR_LEN); 52364358Sarchie break; 52464653Sarchie case NGM_ETHER_SET_ENADDR: 52564653Sarchie { 52664653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 52764653Sarchie error = EINVAL; 52864653Sarchie break; 52964653Sarchie } 53064653Sarchie error = if_setlladdr(priv->ifp, 53164653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 53264653Sarchie break; 53364653Sarchie } 53464653Sarchie case NGM_ETHER_GET_PROMISC: 53564653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 53664653Sarchie if (resp == NULL) { 53764653Sarchie error = ENOMEM; 53864653Sarchie break; 53964653Sarchie } 54064653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 54164653Sarchie break; 54264358Sarchie case NGM_ETHER_SET_PROMISC: 54364358Sarchie { 54464358Sarchie u_char want; 54564358Sarchie 54664358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 54764358Sarchie error = EINVAL; 54864358Sarchie break; 54964358Sarchie } 55064358Sarchie want = !!*((u_int32_t *)msg->data); 55164358Sarchie if (want ^ priv->promisc) { 55264358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 55364358Sarchie break; 55464358Sarchie priv->promisc = want; 55564358Sarchie } 55664358Sarchie break; 55764358Sarchie } 55864653Sarchie case NGM_ETHER_GET_AUTOSRC: 55964653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 56064653Sarchie if (resp == NULL) { 56164653Sarchie error = ENOMEM; 56264653Sarchie break; 56364653Sarchie } 56464653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 56564653Sarchie break; 56664358Sarchie case NGM_ETHER_SET_AUTOSRC: 56764358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 56864358Sarchie error = EINVAL; 56964358Sarchie break; 57064358Sarchie } 57164358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 57264358Sarchie break; 57362143Sarchie default: 57462143Sarchie error = EINVAL; 57562143Sarchie break; 57662143Sarchie } 57762143Sarchie break; 57862143Sarchie default: 57962143Sarchie error = EINVAL; 58062143Sarchie break; 58162143Sarchie } 58262143Sarchie if (rptr) 58362143Sarchie *rptr = resp; 58462143Sarchie else if (resp != NULL) 58562143Sarchie FREE(resp, M_NETGRAPH); 58662143Sarchie FREE(msg, M_NETGRAPH); 58762143Sarchie return (error); 58862143Sarchie} 58962143Sarchie 59062143Sarchie/* 59162143Sarchie * Receive data on a hook. 59262143Sarchie */ 59362143Sarchiestatic int 59462143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 59562143Sarchie struct mbuf **ret_m, meta_p *ret_meta) 59662143Sarchie{ 59762143Sarchie const node_p node = hook->node; 59862143Sarchie const priv_p priv = node->private; 59962143Sarchie 60062143Sarchie if (hook == priv->lower) 60162143Sarchie return ng_ether_rcv_lower(node, m, meta); 60262143Sarchie if (hook == priv->upper) 60362143Sarchie return ng_ether_rcv_upper(node, m, meta); 60462143Sarchie panic("%s: weird hook", __FUNCTION__); 60562143Sarchie} 60662143Sarchie 60762143Sarchie/* 60862143Sarchie * Handle an mbuf received on the "lower" hook. 60962143Sarchie */ 61062143Sarchiestatic int 61162143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 61262143Sarchie{ 61362143Sarchie const priv_p priv = node->private; 61462143Sarchie 61562143Sarchie /* Make sure header is fully pulled up */ 61662143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 61762143Sarchie NG_FREE_DATA(m, meta); 61862143Sarchie return (EINVAL); 61962143Sarchie } 62062143Sarchie if (m->m_len < sizeof(struct ether_header) 62162143Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 62262143Sarchie NG_FREE_META(meta); 62362143Sarchie return (ENOBUFS); 62462143Sarchie } 62562143Sarchie 62664358Sarchie /* Drop in the MAC address if desired */ 62764358Sarchie if (priv->autoSrcAddr) { 62864358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 62964358Sarchie mtod(m, struct ether_header *)->ether_shost, 63064358Sarchie ETHER_ADDR_LEN); 63164358Sarchie } 63262678Sjulian 63362143Sarchie /* Send it on its way */ 63462143Sarchie NG_FREE_META(meta); 63562143Sarchie return ether_output_frame(priv->ifp, m); 63662143Sarchie} 63762143Sarchie 63862143Sarchie/* 63962143Sarchie * Handle an mbuf received on the "upper" hook. 64062143Sarchie */ 64162143Sarchiestatic int 64262143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 64362143Sarchie{ 64462143Sarchie const priv_p priv = node->private; 64562143Sarchie struct ether_header *eh; 64662143Sarchie 64762143Sarchie /* Check length and pull off header */ 64862143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 64962143Sarchie NG_FREE_DATA(m, meta); 65062143Sarchie return (EINVAL); 65162143Sarchie } 65262143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 65362143Sarchie NG_FREE_META(meta); 65462143Sarchie return (ENOBUFS); 65562143Sarchie } 65662143Sarchie eh = mtod(m, struct ether_header *); 65762143Sarchie m->m_data += sizeof(*eh); 65862143Sarchie m->m_len -= sizeof(*eh); 65962143Sarchie m->m_pkthdr.len -= sizeof(*eh); 66062143Sarchie 66162143Sarchie /* Route packet back in */ 66262143Sarchie NG_FREE_META(meta); 66362143Sarchie ether_demux(priv->ifp, eh, m); 66462143Sarchie return (0); 66562143Sarchie} 66662143Sarchie 66762143Sarchie/* 66862143Sarchie * Shutdown node. This resets the node but does not remove it. 66962143Sarchie */ 67062143Sarchiestatic int 67162143Sarchieng_ether_rmnode(node_p node) 67262143Sarchie{ 67364358Sarchie const priv_p priv = node->private; 67464358Sarchie 67562143Sarchie ng_cutlinks(node); 67662143Sarchie node->flags &= ~NG_INVALID; /* bounce back to life */ 67764358Sarchie if (priv->promisc) { /* disable promiscuous mode */ 67864358Sarchie (void)ifpromisc(priv->ifp, 0); 67964358Sarchie priv->promisc = 0; 68064358Sarchie } 68164358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 68262143Sarchie return (0); 68362143Sarchie} 68462143Sarchie 68562143Sarchie/* 68662143Sarchie * Hook disconnection. 68762143Sarchie */ 68862143Sarchiestatic int 68962143Sarchieng_ether_disconnect(hook_p hook) 69062143Sarchie{ 69162143Sarchie const priv_p priv = hook->node->private; 69262143Sarchie 69362143Sarchie if (hook == priv->upper) 69462143Sarchie priv->upper = NULL; 69562143Sarchie else if (hook == priv->lower) { 69662143Sarchie priv->lower = NULL; 69762143Sarchie priv->lowerOrphan = 0; 69862143Sarchie } else 69962143Sarchie panic("%s: weird hook", __FUNCTION__); 70062143Sarchie return (0); 70162143Sarchie} 70262143Sarchie 70364653Sarchiestatic int 70464653Sarchieng_enaddr_parse(const struct ng_parse_type *type, 70564653Sarchie const char *s, int *const off, const u_char *const start, 70664653Sarchie u_char *const buf, int *const buflen) 70764653Sarchie{ 70864653Sarchie char *eptr; 70964653Sarchie u_long val; 71064653Sarchie int i; 71164653Sarchie 71264653Sarchie if (*buflen < ETHER_ADDR_LEN) 71364653Sarchie return (ERANGE); 71464653Sarchie for (i = 0; i < ETHER_ADDR_LEN; i++) { 71564653Sarchie val = strtoul(s + *off, &eptr, 16); 71664653Sarchie if (val > 0xff || eptr == s + *off) 71764653Sarchie return (EINVAL); 71864653Sarchie buf[i] = (u_char)val; 71964653Sarchie *off = (eptr - s); 72064653Sarchie if (i < ETHER_ADDR_LEN - 1) { 72164653Sarchie if (*eptr != ':') 72264653Sarchie return (EINVAL); 72364653Sarchie (*off)++; 72464653Sarchie } 72564653Sarchie } 72664653Sarchie *buflen = ETHER_ADDR_LEN; 72764653Sarchie return (0); 72864653Sarchie} 72964653Sarchie 73064653Sarchiestatic int 73164653Sarchieng_enaddr_unparse(const struct ng_parse_type *type, 73264653Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 73364653Sarchie{ 73464653Sarchie int len; 73564653Sarchie 73664653Sarchie len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 73764653Sarchie data[0], data[1], data[2], data[3], data[4], data[5]); 73864653Sarchie if (len >= cbuflen) 73964653Sarchie return (ERANGE); 74064653Sarchie *off += ETHER_ADDR_LEN; 74164653Sarchie return (0); 74264653Sarchie} 74364653Sarchie 74462143Sarchie/****************************************************************** 74562143Sarchie INITIALIZATION 74662143Sarchie******************************************************************/ 74762143Sarchie 74862143Sarchie/* 74962143Sarchie * Handle loading and unloading for this node type. 75062143Sarchie */ 75162143Sarchiestatic int 75262143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 75362143Sarchie{ 75462143Sarchie struct ifnet *ifp; 75562143Sarchie int error = 0; 75662143Sarchie int s; 75762143Sarchie 75862143Sarchie s = splnet(); 75962143Sarchie switch (event) { 76062143Sarchie case MOD_LOAD: 76162143Sarchie 76262143Sarchie /* Register function hooks */ 76362143Sarchie if (ng_ether_attach_p != NULL) { 76462143Sarchie error = EEXIST; 76562143Sarchie break; 76662143Sarchie } 76762143Sarchie ng_ether_attach_p = ng_ether_attach; 76862143Sarchie ng_ether_detach_p = ng_ether_detach; 76962143Sarchie ng_ether_output_p = ng_ether_output; 77062143Sarchie ng_ether_input_p = ng_ether_input; 77162143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 77262143Sarchie 77362143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 77462143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 77562143Sarchie if (ifp->if_type == IFT_ETHER) 77662143Sarchie ng_ether_attach(ifp); 77762143Sarchie } 77862143Sarchie break; 77962143Sarchie 78062143Sarchie case MOD_UNLOAD: 78162143Sarchie 78262143Sarchie /* 78362143Sarchie * Note that the base code won't try to unload us until 78462143Sarchie * all nodes have been removed, and that can't happen 78562143Sarchie * until all Ethernet interfaces are removed. In any 78662143Sarchie * case, we know there are no nodes left if the action 78762143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 78862143Sarchie */ 78962143Sarchie 79062143Sarchie /* Unregister function hooks */ 79162143Sarchie ng_ether_attach_p = NULL; 79262143Sarchie ng_ether_detach_p = NULL; 79362143Sarchie ng_ether_output_p = NULL; 79462143Sarchie ng_ether_input_p = NULL; 79562143Sarchie ng_ether_input_orphan_p = NULL; 79662143Sarchie break; 79762143Sarchie 79862143Sarchie default: 79962143Sarchie error = EOPNOTSUPP; 80062143Sarchie break; 80162143Sarchie } 80262143Sarchie splx(s); 80362143Sarchie return (error); 80462143Sarchie} 80562143Sarchie 806