ng_ether.c revision 69922
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 69922 2000-12-12 18:52:14Z julian $ 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; 10369922Sjulianstatic ng_connect_t ng_ether_connect; 10462143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10562143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 10662143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 10762143Sarchie 10864653Sarchie/* Parse type for an Ethernet address */ 10964653Sarchiestatic ng_parse_t ng_enaddr_parse; 11064653Sarchiestatic ng_unparse_t ng_enaddr_unparse; 11164653Sarchieconst struct ng_parse_type ng_ether_enaddr_type = { 11264653Sarchie NULL, 11364653Sarchie NULL, 11464653Sarchie NULL, 11564653Sarchie ng_enaddr_parse, 11664653Sarchie ng_enaddr_unparse, 11764653Sarchie NULL, /* no such thing as a "default" EN address */ 11864653Sarchie 0 11964358Sarchie}; 12064358Sarchie 12162143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12262143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 12362143Sarchie { 12462143Sarchie NGM_ETHER_COOKIE, 12562143Sarchie NGM_ETHER_GET_IFNAME, 12662143Sarchie "getifname", 12762143Sarchie NULL, 12862143Sarchie &ng_parse_string_type 12962143Sarchie }, 13062143Sarchie { 13162143Sarchie NGM_ETHER_COOKIE, 13262143Sarchie NGM_ETHER_GET_IFINDEX, 13362143Sarchie "getifindex", 13462143Sarchie NULL, 13562143Sarchie &ng_parse_int32_type 13662143Sarchie }, 13764358Sarchie { 13864358Sarchie NGM_ETHER_COOKIE, 13964358Sarchie NGM_ETHER_GET_ENADDR, 14064358Sarchie "getenaddr", 14164358Sarchie NULL, 14264358Sarchie &ng_ether_enaddr_type 14364358Sarchie }, 14464358Sarchie { 14564358Sarchie NGM_ETHER_COOKIE, 14664653Sarchie NGM_ETHER_SET_ENADDR, 14764653Sarchie "setenaddr", 14864653Sarchie &ng_ether_enaddr_type, 14964653Sarchie NULL 15064653Sarchie }, 15164653Sarchie { 15264653Sarchie NGM_ETHER_COOKIE, 15364653Sarchie NGM_ETHER_GET_PROMISC, 15464653Sarchie "getpromisc", 15564653Sarchie NULL, 15664653Sarchie &ng_parse_int32_type 15764653Sarchie }, 15864653Sarchie { 15964653Sarchie NGM_ETHER_COOKIE, 16064358Sarchie NGM_ETHER_SET_PROMISC, 16164358Sarchie "setpromisc", 16264358Sarchie &ng_parse_int32_type, 16364358Sarchie NULL 16464358Sarchie }, 16564358Sarchie { 16664358Sarchie NGM_ETHER_COOKIE, 16764653Sarchie NGM_ETHER_GET_AUTOSRC, 16864653Sarchie "getautosrc", 16964653Sarchie NULL, 17064653Sarchie &ng_parse_int32_type 17164653Sarchie }, 17264653Sarchie { 17364653Sarchie NGM_ETHER_COOKIE, 17464358Sarchie NGM_ETHER_SET_AUTOSRC, 17564358Sarchie "setautosrc", 17664358Sarchie &ng_parse_int32_type, 17764358Sarchie NULL 17864358Sarchie }, 17962143Sarchie { 0 } 18062143Sarchie}; 18162143Sarchie 18262143Sarchiestatic struct ng_type ng_ether_typestruct = { 18362143Sarchie NG_VERSION, 18462143Sarchie NG_ETHER_NODE_TYPE, 18562143Sarchie ng_ether_mod_event, 18662143Sarchie ng_ether_constructor, 18762143Sarchie ng_ether_rcvmsg, 18862143Sarchie ng_ether_rmnode, 18962143Sarchie ng_ether_newhook, 19062143Sarchie NULL, 19169922Sjulian ng_ether_connect, 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/* 24569922Sjulian * Handle a packet that has come in on an ethernet 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 int error; 25662143Sarchie 25762143Sarchie /* Glue Ethernet header back on */ 25862143Sarchie if ((error = ng_ether_glueback_header(mp, eh)) != 0) 25962143Sarchie return; 26062143Sarchie 26162143Sarchie /* Send out lower/orphan hook */ 26269922Sjulian NG_SEND_DATA_ONLY(error, priv->lower, *mp); 26362143Sarchie *mp = NULL; 26462143Sarchie} 26562143Sarchie 26662143Sarchie/* 26762143Sarchie * Handle a packet that is going out on an interface. 26862143Sarchie * The Ethernet header is already attached to the mbuf. 26962143Sarchie */ 27062143Sarchiestatic int 27162143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 27262143Sarchie{ 27362143Sarchie const node_p node = IFP2NG(ifp); 27462143Sarchie const priv_p priv = node->private; 27562143Sarchie meta_p meta = NULL; 27662143Sarchie int error = 0; 27762143Sarchie 27862143Sarchie /* If "upper" hook not connected, let packet continue */ 27962143Sarchie if (priv->upper == NULL) 28062143Sarchie return (0); 28162143Sarchie 28262143Sarchie /* Send it out "upper" hook */ 28369922Sjulian NG_SEND_DATA_RET(error, priv->upper, *mp, meta, NULL); 28462143Sarchie 28562143Sarchie /* If we got a reflected packet back, handle it */ 28662143Sarchie if (error == 0 && *mp != NULL) { 28762143Sarchie error = ng_ether_rcv_upper(node, *mp, meta); 28862143Sarchie *mp = NULL; 28962143Sarchie } 29062143Sarchie return (error); 29162143Sarchie} 29262143Sarchie 29362143Sarchie/* 29462143Sarchie * A new Ethernet interface has been attached. 29562143Sarchie * Create a new node for it, etc. 29662143Sarchie */ 29762143Sarchiestatic void 29862143Sarchieng_ether_attach(struct ifnet *ifp) 29962143Sarchie{ 30062143Sarchie char name[IFNAMSIZ + 1]; 30162143Sarchie priv_p priv; 30262143Sarchie node_p node; 30362143Sarchie 30462143Sarchie /* Create node */ 30562143Sarchie KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__)); 30662143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 30762143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 30862143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 30962143Sarchie __FUNCTION__, "create node", name); 31062143Sarchie return; 31162143Sarchie } 31262143Sarchie 31362143Sarchie /* Allocate private data */ 31468876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 31562143Sarchie if (priv == NULL) { 31662143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 31762143Sarchie __FUNCTION__, "allocate memory", name); 31862143Sarchie ng_unref(node); 31962143Sarchie return; 32062143Sarchie } 32162143Sarchie node->private = priv; 32262143Sarchie priv->ifp = ifp; 32362143Sarchie IFP2NG(ifp) = node; 32464358Sarchie priv->autoSrcAddr = 1; 32562143Sarchie 32662143Sarchie /* Try to give the node the same name as the interface */ 32762143Sarchie if (ng_name_node(node, name) != 0) { 32862143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 32962143Sarchie __FUNCTION__, name); 33062143Sarchie } 33162143Sarchie} 33262143Sarchie 33362143Sarchie/* 33462143Sarchie * An Ethernet interface is being detached. 33562143Sarchie * Destroy its node. 33662143Sarchie */ 33762143Sarchiestatic void 33862143Sarchieng_ether_detach(struct ifnet *ifp) 33962143Sarchie{ 34062143Sarchie const node_p node = IFP2NG(ifp); 34162143Sarchie priv_p priv; 34262143Sarchie 34362143Sarchie if (node == NULL) /* no node (why not?), ignore */ 34462143Sarchie return; 34562143Sarchie ng_rmnode(node); /* break all links to other nodes */ 34663195Sarchie node->flags |= NG_INVALID; 34763543Sarchie ng_unname(node); /* free name (and its reference) */ 34862143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 34962143Sarchie priv = node->private; /* free node private info */ 35062143Sarchie bzero(priv, sizeof(*priv)); 35162143Sarchie FREE(priv, M_NETGRAPH); 35262143Sarchie node->private = NULL; 35362143Sarchie ng_unref(node); /* free node itself */ 35462143Sarchie} 35562143Sarchie 35662143Sarchie/* 35762143Sarchie * Optimization for gluing the Ethernet header back onto 35862143Sarchie * the front of an incoming packet. 35962143Sarchie */ 36062143Sarchiestatic int 36162143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 36262143Sarchie{ 36362143Sarchie struct mbuf *m = *mp; 36462143Sarchie uintfptr_t room; 36562143Sarchie int error = 0; 36662143Sarchie 36762143Sarchie /* 36862143Sarchie * Possibly the header is already on the front. 36962143Sarchie * If this is the case so just move the markers back 37062143Sarchie * to re-include it. We lucked out. 37162143Sarchie * This allows us to avoid a yucky m_pullup 37262143Sarchie * in later nodes if it works. 37362143Sarchie */ 37462143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 37562143Sarchie m->m_len += sizeof(*eh); 37662143Sarchie m->m_data -= sizeof(*eh); 37762143Sarchie m->m_pkthdr.len += sizeof(*eh); 37862143Sarchie goto done; 37962143Sarchie } 38062143Sarchie 38162143Sarchie /* 38262143Sarchie * Alternatively there may be room even though 38362143Sarchie * it is stored somewhere else. If so, copy it in. 38462143Sarchie * This only safe because we KNOW that this packet has 38562143Sarchie * just been generated by an ethernet card, so there are 38662143Sarchie * no aliases to the buffer (not so for outgoing packets). 38762143Sarchie * Nearly all ethernet cards will end up producing mbufs 38862143Sarchie * that fall into these cases. So we are not optimizing 38962143Sarchie * contorted cases. 39062143Sarchie */ 39162143Sarchie if ((m->m_flags & M_EXT) != 0) { 39262143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 39362143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 39462143Sarchie room = 0; 39562143Sarchie } else 39662143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 39762143Sarchie 39862143Sarchie /* 39962143Sarchie * If we have room, just copy it and adjust 40062143Sarchie */ 40162143Sarchie if (room >= sizeof(*eh)) { 40262143Sarchie m->m_len += sizeof(*eh); 40362143Sarchie m->m_data -= sizeof(*eh); 40462143Sarchie m->m_pkthdr.len += sizeof(*eh); 40562143Sarchie goto copy; 40662143Sarchie } 40762143Sarchie 40862143Sarchie /* 40962143Sarchie * Doing anything more is likely to get more 41062143Sarchie * expensive than it's worth.. 41162143Sarchie * it's probable that everything else is in one 41262143Sarchie * big lump. The next node will do an m_pullup() 41362143Sarchie * for exactly the amount of data it needs and 41462143Sarchie * hopefully everything after that will not 41562143Sarchie * need one. So let's just use M_PREPEND. 41662143Sarchie */ 41762143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 41862143Sarchie if (m == NULL) { 41962143Sarchie error = ENOBUFS; 42062143Sarchie goto done; 42162143Sarchie } 42262143Sarchie 42362143Sarchiecopy: 42462143Sarchie /* Copy header and return (possibly new) mbuf */ 42562143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 42662143Sarchiedone: 42762143Sarchie *mp = m; 42862143Sarchie return error; 42962143Sarchie} 43062143Sarchie 43162143Sarchie/****************************************************************** 43262143Sarchie NETGRAPH NODE METHODS 43362143Sarchie******************************************************************/ 43462143Sarchie 43562143Sarchie/* 43662143Sarchie * It is not possible or allowable to create a node of this type. 43762143Sarchie * Nodes get created when the interface is attached (or, when 43862143Sarchie * this node type's KLD is loaded). 43962143Sarchie */ 44062143Sarchiestatic int 44162143Sarchieng_ether_constructor(node_p *nodep) 44262143Sarchie{ 44362143Sarchie return (EINVAL); 44462143Sarchie} 44562143Sarchie 44662143Sarchie/* 44762143Sarchie * Check for attaching a new hook. 44862143Sarchie */ 44962143Sarchiestatic int 45062143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 45162143Sarchie{ 45262143Sarchie const priv_p priv = node->private; 45362143Sarchie u_char orphan = priv->lowerOrphan; 45462143Sarchie hook_p *hookptr; 45562143Sarchie 45662143Sarchie /* Divert hook is an alias for lower */ 45762143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 45862143Sarchie name = NG_ETHER_HOOK_LOWER; 45962143Sarchie 46062143Sarchie /* Which hook? */ 46162143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 46262143Sarchie hookptr = &priv->upper; 46362143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 46462143Sarchie hookptr = &priv->lower; 46562143Sarchie orphan = 0; 46662143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 46762143Sarchie hookptr = &priv->lower; 46862143Sarchie orphan = 1; 46962143Sarchie } else 47062143Sarchie return (EINVAL); 47162143Sarchie 47262143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 47362143Sarchie if (*hookptr != NULL) 47462143Sarchie return (EISCONN); 47562143Sarchie 47662143Sarchie /* OK */ 47762143Sarchie *hookptr = hook; 47862143Sarchie priv->lowerOrphan = orphan; 47962143Sarchie return (0); 48062143Sarchie} 48162143Sarchie 48262143Sarchie/* 48369922Sjulian * Hooks are attached, adjust to force queueing. 48469922Sjulian * We don't really care which hook it is. 48569922Sjulian * they should all be queuing for outgoing data. 48669922Sjulian */ 48769922Sjulianstatic int 48869922Sjulianng_ether_connect(hook_p hook) 48969922Sjulian{ 49069922Sjulian hook->peer->flags |= HK_QUEUE; 49169922Sjulian return (0); 49269922Sjulian} 49369922Sjulian 49469922Sjulian/* 49562143Sarchie * Receive an incoming control message. 49662143Sarchie */ 49762143Sarchiestatic int 49862143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 49962143Sarchie struct ng_mesg **rptr, hook_p lasthook) 50062143Sarchie{ 50162143Sarchie const priv_p priv = node->private; 50262143Sarchie struct ng_mesg *resp = NULL; 50362143Sarchie int error = 0; 50462143Sarchie 50562143Sarchie switch (msg->header.typecookie) { 50662143Sarchie case NGM_ETHER_COOKIE: 50762143Sarchie switch (msg->header.cmd) { 50862143Sarchie case NGM_ETHER_GET_IFNAME: 50962143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 51062143Sarchie if (resp == NULL) { 51162143Sarchie error = ENOMEM; 51262143Sarchie break; 51362143Sarchie } 51462143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 51562143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 51662143Sarchie break; 51762143Sarchie case NGM_ETHER_GET_IFINDEX: 51862143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 51962143Sarchie if (resp == NULL) { 52062143Sarchie error = ENOMEM; 52162143Sarchie break; 52262143Sarchie } 52362143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 52462143Sarchie break; 52564358Sarchie case NGM_ETHER_GET_ENADDR: 52664358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 52764358Sarchie if (resp == NULL) { 52864358Sarchie error = ENOMEM; 52964358Sarchie break; 53064358Sarchie } 53164358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 53264358Sarchie resp->data, ETHER_ADDR_LEN); 53364358Sarchie break; 53464653Sarchie case NGM_ETHER_SET_ENADDR: 53564653Sarchie { 53664653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 53764653Sarchie error = EINVAL; 53864653Sarchie break; 53964653Sarchie } 54064653Sarchie error = if_setlladdr(priv->ifp, 54164653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 54264653Sarchie break; 54364653Sarchie } 54464653Sarchie case NGM_ETHER_GET_PROMISC: 54564653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 54664653Sarchie if (resp == NULL) { 54764653Sarchie error = ENOMEM; 54864653Sarchie break; 54964653Sarchie } 55064653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 55164653Sarchie break; 55264358Sarchie case NGM_ETHER_SET_PROMISC: 55364358Sarchie { 55464358Sarchie u_char want; 55564358Sarchie 55664358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 55764358Sarchie error = EINVAL; 55864358Sarchie break; 55964358Sarchie } 56064358Sarchie want = !!*((u_int32_t *)msg->data); 56164358Sarchie if (want ^ priv->promisc) { 56264358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 56364358Sarchie break; 56464358Sarchie priv->promisc = want; 56564358Sarchie } 56664358Sarchie break; 56764358Sarchie } 56864653Sarchie case NGM_ETHER_GET_AUTOSRC: 56964653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 57064653Sarchie if (resp == NULL) { 57164653Sarchie error = ENOMEM; 57264653Sarchie break; 57364653Sarchie } 57464653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 57564653Sarchie break; 57664358Sarchie case NGM_ETHER_SET_AUTOSRC: 57764358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 57864358Sarchie error = EINVAL; 57964358Sarchie break; 58064358Sarchie } 58164358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 58264358Sarchie break; 58362143Sarchie default: 58462143Sarchie error = EINVAL; 58562143Sarchie break; 58662143Sarchie } 58762143Sarchie break; 58862143Sarchie default: 58962143Sarchie error = EINVAL; 59062143Sarchie break; 59162143Sarchie } 59262143Sarchie if (rptr) 59362143Sarchie *rptr = resp; 59462143Sarchie else if (resp != NULL) 59562143Sarchie FREE(resp, M_NETGRAPH); 59662143Sarchie FREE(msg, M_NETGRAPH); 59762143Sarchie return (error); 59862143Sarchie} 59962143Sarchie 60062143Sarchie/* 60162143Sarchie * Receive data on a hook. 60262143Sarchie */ 60362143Sarchiestatic int 60462143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 60569922Sjulian struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 60662143Sarchie{ 60762143Sarchie const node_p node = hook->node; 60862143Sarchie const priv_p priv = node->private; 60962143Sarchie 61062143Sarchie if (hook == priv->lower) 61162143Sarchie return ng_ether_rcv_lower(node, m, meta); 61262143Sarchie if (hook == priv->upper) 61362143Sarchie return ng_ether_rcv_upper(node, m, meta); 61462143Sarchie panic("%s: weird hook", __FUNCTION__); 61562143Sarchie} 61662143Sarchie 61762143Sarchie/* 61862143Sarchie * Handle an mbuf received on the "lower" hook. 61962143Sarchie */ 62062143Sarchiestatic int 62162143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 62262143Sarchie{ 62362143Sarchie const priv_p priv = node->private; 62462143Sarchie 62562143Sarchie /* Make sure header is fully pulled up */ 62662143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 62762143Sarchie NG_FREE_DATA(m, meta); 62862143Sarchie return (EINVAL); 62962143Sarchie } 63062143Sarchie if (m->m_len < sizeof(struct ether_header) 63162143Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 63262143Sarchie NG_FREE_META(meta); 63362143Sarchie return (ENOBUFS); 63462143Sarchie } 63562143Sarchie 63664358Sarchie /* Drop in the MAC address if desired */ 63764358Sarchie if (priv->autoSrcAddr) { 63864358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 63964358Sarchie mtod(m, struct ether_header *)->ether_shost, 64064358Sarchie ETHER_ADDR_LEN); 64164358Sarchie } 64262678Sjulian 64362143Sarchie /* Send it on its way */ 64462143Sarchie NG_FREE_META(meta); 64562143Sarchie return ether_output_frame(priv->ifp, m); 64662143Sarchie} 64762143Sarchie 64862143Sarchie/* 64962143Sarchie * Handle an mbuf received on the "upper" hook. 65062143Sarchie */ 65162143Sarchiestatic int 65262143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 65362143Sarchie{ 65462143Sarchie const priv_p priv = node->private; 65562143Sarchie struct ether_header *eh; 65662143Sarchie 65762143Sarchie /* Check length and pull off header */ 65862143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 65962143Sarchie NG_FREE_DATA(m, meta); 66062143Sarchie return (EINVAL); 66162143Sarchie } 66262143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 66362143Sarchie NG_FREE_META(meta); 66462143Sarchie return (ENOBUFS); 66562143Sarchie } 66662143Sarchie eh = mtod(m, struct ether_header *); 66762143Sarchie m->m_data += sizeof(*eh); 66862143Sarchie m->m_len -= sizeof(*eh); 66962143Sarchie m->m_pkthdr.len -= sizeof(*eh); 67066061Sjulian m->m_pkthdr.rcvif = priv->ifp; 67162143Sarchie 67262143Sarchie /* Route packet back in */ 67362143Sarchie NG_FREE_META(meta); 67462143Sarchie ether_demux(priv->ifp, eh, m); 67562143Sarchie return (0); 67662143Sarchie} 67762143Sarchie 67862143Sarchie/* 67962143Sarchie * Shutdown node. This resets the node but does not remove it. 68062143Sarchie */ 68162143Sarchiestatic int 68262143Sarchieng_ether_rmnode(node_p node) 68362143Sarchie{ 68464358Sarchie const priv_p priv = node->private; 68564358Sarchie 68662143Sarchie ng_cutlinks(node); 68762143Sarchie node->flags &= ~NG_INVALID; /* bounce back to life */ 68864358Sarchie if (priv->promisc) { /* disable promiscuous mode */ 68964358Sarchie (void)ifpromisc(priv->ifp, 0); 69064358Sarchie priv->promisc = 0; 69164358Sarchie } 69264358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 69362143Sarchie return (0); 69462143Sarchie} 69562143Sarchie 69662143Sarchie/* 69762143Sarchie * Hook disconnection. 69862143Sarchie */ 69962143Sarchiestatic int 70062143Sarchieng_ether_disconnect(hook_p hook) 70162143Sarchie{ 70262143Sarchie const priv_p priv = hook->node->private; 70362143Sarchie 70462143Sarchie if (hook == priv->upper) 70562143Sarchie priv->upper = NULL; 70662143Sarchie else if (hook == priv->lower) { 70762143Sarchie priv->lower = NULL; 70862143Sarchie priv->lowerOrphan = 0; 70962143Sarchie } else 71062143Sarchie panic("%s: weird hook", __FUNCTION__); 71169840Sarchie if (hook->node->numhooks == 0) 71269840Sarchie ng_rmnode(hook->node); /* reset node */ 71362143Sarchie return (0); 71462143Sarchie} 71562143Sarchie 71664653Sarchiestatic int 71764653Sarchieng_enaddr_parse(const struct ng_parse_type *type, 71864653Sarchie const char *s, int *const off, const u_char *const start, 71964653Sarchie u_char *const buf, int *const buflen) 72064653Sarchie{ 72164653Sarchie char *eptr; 72264653Sarchie u_long val; 72364653Sarchie int i; 72464653Sarchie 72564653Sarchie if (*buflen < ETHER_ADDR_LEN) 72664653Sarchie return (ERANGE); 72764653Sarchie for (i = 0; i < ETHER_ADDR_LEN; i++) { 72864653Sarchie val = strtoul(s + *off, &eptr, 16); 72964653Sarchie if (val > 0xff || eptr == s + *off) 73064653Sarchie return (EINVAL); 73164653Sarchie buf[i] = (u_char)val; 73264653Sarchie *off = (eptr - s); 73364653Sarchie if (i < ETHER_ADDR_LEN - 1) { 73464653Sarchie if (*eptr != ':') 73564653Sarchie return (EINVAL); 73664653Sarchie (*off)++; 73764653Sarchie } 73864653Sarchie } 73964653Sarchie *buflen = ETHER_ADDR_LEN; 74064653Sarchie return (0); 74164653Sarchie} 74264653Sarchie 74364653Sarchiestatic int 74464653Sarchieng_enaddr_unparse(const struct ng_parse_type *type, 74564653Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 74664653Sarchie{ 74764653Sarchie int len; 74864653Sarchie 74964653Sarchie len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 75065305Sarchie data[*off], data[*off + 1], data[*off + 2], 75165305Sarchie data[*off + 3], data[*off + 4], data[*off + 5]); 75264653Sarchie if (len >= cbuflen) 75364653Sarchie return (ERANGE); 75464653Sarchie *off += ETHER_ADDR_LEN; 75564653Sarchie return (0); 75664653Sarchie} 75764653Sarchie 75862143Sarchie/****************************************************************** 75962143Sarchie INITIALIZATION 76062143Sarchie******************************************************************/ 76162143Sarchie 76262143Sarchie/* 76362143Sarchie * Handle loading and unloading for this node type. 76462143Sarchie */ 76562143Sarchiestatic int 76662143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 76762143Sarchie{ 76862143Sarchie struct ifnet *ifp; 76962143Sarchie int error = 0; 77062143Sarchie int s; 77162143Sarchie 77262143Sarchie s = splnet(); 77362143Sarchie switch (event) { 77462143Sarchie case MOD_LOAD: 77562143Sarchie 77662143Sarchie /* Register function hooks */ 77762143Sarchie if (ng_ether_attach_p != NULL) { 77862143Sarchie error = EEXIST; 77962143Sarchie break; 78062143Sarchie } 78162143Sarchie ng_ether_attach_p = ng_ether_attach; 78262143Sarchie ng_ether_detach_p = ng_ether_detach; 78362143Sarchie ng_ether_output_p = ng_ether_output; 78462143Sarchie ng_ether_input_p = ng_ether_input; 78562143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 78662143Sarchie 78762143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 78862143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 78962143Sarchie if (ifp->if_type == IFT_ETHER) 79062143Sarchie ng_ether_attach(ifp); 79162143Sarchie } 79262143Sarchie break; 79362143Sarchie 79462143Sarchie case MOD_UNLOAD: 79562143Sarchie 79662143Sarchie /* 79762143Sarchie * Note that the base code won't try to unload us until 79862143Sarchie * all nodes have been removed, and that can't happen 79962143Sarchie * until all Ethernet interfaces are removed. In any 80062143Sarchie * case, we know there are no nodes left if the action 80162143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 80262143Sarchie */ 80362143Sarchie 80462143Sarchie /* Unregister function hooks */ 80562143Sarchie ng_ether_attach_p = NULL; 80662143Sarchie ng_ether_detach_p = NULL; 80762143Sarchie ng_ether_output_p = NULL; 80862143Sarchie ng_ether_input_p = NULL; 80962143Sarchie ng_ether_input_orphan_p = NULL; 81062143Sarchie break; 81162143Sarchie 81262143Sarchie default: 81362143Sarchie error = EOPNOTSUPP; 81462143Sarchie break; 81562143Sarchie } 81662143Sarchie splx(s); 81762143Sarchie return (error); 81862143Sarchie} 81962143Sarchie 820