ng_ether.c revision 69840
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 69840 2000-12-11 03:36:26Z 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 */ 31568876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 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 node->private = priv; 32362143Sarchie priv->ifp = ifp; 32462143Sarchie IFP2NG(ifp) = node; 32564358Sarchie priv->autoSrcAddr = 1; 32662143Sarchie 32762143Sarchie /* Try to give the node the same name as the interface */ 32862143Sarchie if (ng_name_node(node, name) != 0) { 32962143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 33062143Sarchie __FUNCTION__, name); 33162143Sarchie } 33262143Sarchie} 33362143Sarchie 33462143Sarchie/* 33562143Sarchie * An Ethernet interface is being detached. 33662143Sarchie * Destroy its node. 33762143Sarchie */ 33862143Sarchiestatic void 33962143Sarchieng_ether_detach(struct ifnet *ifp) 34062143Sarchie{ 34162143Sarchie const node_p node = IFP2NG(ifp); 34262143Sarchie priv_p priv; 34362143Sarchie 34462143Sarchie if (node == NULL) /* no node (why not?), ignore */ 34562143Sarchie return; 34662143Sarchie ng_rmnode(node); /* break all links to other nodes */ 34763195Sarchie node->flags |= NG_INVALID; 34863543Sarchie ng_unname(node); /* free name (and its reference) */ 34962143Sarchie IFP2NG(ifp) = NULL; /* detach node from interface */ 35062143Sarchie priv = node->private; /* free node private info */ 35162143Sarchie bzero(priv, sizeof(*priv)); 35262143Sarchie FREE(priv, M_NETGRAPH); 35362143Sarchie node->private = NULL; 35462143Sarchie ng_unref(node); /* free node itself */ 35562143Sarchie} 35662143Sarchie 35762143Sarchie/* 35862143Sarchie * Optimization for gluing the Ethernet header back onto 35962143Sarchie * the front of an incoming packet. 36062143Sarchie */ 36162143Sarchiestatic int 36262143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 36362143Sarchie{ 36462143Sarchie struct mbuf *m = *mp; 36562143Sarchie uintfptr_t room; 36662143Sarchie int error = 0; 36762143Sarchie 36862143Sarchie /* 36962143Sarchie * Possibly the header is already on the front. 37062143Sarchie * If this is the case so just move the markers back 37162143Sarchie * to re-include it. We lucked out. 37262143Sarchie * This allows us to avoid a yucky m_pullup 37362143Sarchie * in later nodes if it works. 37462143Sarchie */ 37562143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 37662143Sarchie m->m_len += sizeof(*eh); 37762143Sarchie m->m_data -= sizeof(*eh); 37862143Sarchie m->m_pkthdr.len += sizeof(*eh); 37962143Sarchie goto done; 38062143Sarchie } 38162143Sarchie 38262143Sarchie /* 38362143Sarchie * Alternatively there may be room even though 38462143Sarchie * it is stored somewhere else. If so, copy it in. 38562143Sarchie * This only safe because we KNOW that this packet has 38662143Sarchie * just been generated by an ethernet card, so there are 38762143Sarchie * no aliases to the buffer (not so for outgoing packets). 38862143Sarchie * Nearly all ethernet cards will end up producing mbufs 38962143Sarchie * that fall into these cases. So we are not optimizing 39062143Sarchie * contorted cases. 39162143Sarchie */ 39262143Sarchie if ((m->m_flags & M_EXT) != 0) { 39362143Sarchie room = mtod(m, caddr_t) - m->m_ext.ext_buf; 39462143Sarchie if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 39562143Sarchie room = 0; 39662143Sarchie } else 39762143Sarchie room = mtod(m, caddr_t) - m->m_pktdat; 39862143Sarchie 39962143Sarchie /* 40062143Sarchie * If we have room, just copy it and adjust 40162143Sarchie */ 40262143Sarchie if (room >= sizeof(*eh)) { 40362143Sarchie m->m_len += sizeof(*eh); 40462143Sarchie m->m_data -= sizeof(*eh); 40562143Sarchie m->m_pkthdr.len += sizeof(*eh); 40662143Sarchie goto copy; 40762143Sarchie } 40862143Sarchie 40962143Sarchie /* 41062143Sarchie * Doing anything more is likely to get more 41162143Sarchie * expensive than it's worth.. 41262143Sarchie * it's probable that everything else is in one 41362143Sarchie * big lump. The next node will do an m_pullup() 41462143Sarchie * for exactly the amount of data it needs and 41562143Sarchie * hopefully everything after that will not 41662143Sarchie * need one. So let's just use M_PREPEND. 41762143Sarchie */ 41862143Sarchie M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 41962143Sarchie if (m == NULL) { 42062143Sarchie error = ENOBUFS; 42162143Sarchie goto done; 42262143Sarchie } 42362143Sarchie 42462143Sarchiecopy: 42562143Sarchie /* Copy header and return (possibly new) mbuf */ 42662143Sarchie bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 42762143Sarchiedone: 42862143Sarchie *mp = m; 42962143Sarchie return error; 43062143Sarchie} 43162143Sarchie 43262143Sarchie/****************************************************************** 43362143Sarchie NETGRAPH NODE METHODS 43462143Sarchie******************************************************************/ 43562143Sarchie 43662143Sarchie/* 43762143Sarchie * It is not possible or allowable to create a node of this type. 43862143Sarchie * Nodes get created when the interface is attached (or, when 43962143Sarchie * this node type's KLD is loaded). 44062143Sarchie */ 44162143Sarchiestatic int 44262143Sarchieng_ether_constructor(node_p *nodep) 44362143Sarchie{ 44462143Sarchie return (EINVAL); 44562143Sarchie} 44662143Sarchie 44762143Sarchie/* 44862143Sarchie * Check for attaching a new hook. 44962143Sarchie */ 45062143Sarchiestatic int 45162143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 45262143Sarchie{ 45362143Sarchie const priv_p priv = node->private; 45462143Sarchie u_char orphan = priv->lowerOrphan; 45562143Sarchie hook_p *hookptr; 45662143Sarchie 45762143Sarchie /* Divert hook is an alias for lower */ 45862143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 45962143Sarchie name = NG_ETHER_HOOK_LOWER; 46062143Sarchie 46162143Sarchie /* Which hook? */ 46262143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 46362143Sarchie hookptr = &priv->upper; 46462143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 46562143Sarchie hookptr = &priv->lower; 46662143Sarchie orphan = 0; 46762143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 46862143Sarchie hookptr = &priv->lower; 46962143Sarchie orphan = 1; 47062143Sarchie } else 47162143Sarchie return (EINVAL); 47262143Sarchie 47362143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 47462143Sarchie if (*hookptr != NULL) 47562143Sarchie return (EISCONN); 47662143Sarchie 47762143Sarchie /* OK */ 47862143Sarchie *hookptr = hook; 47962143Sarchie priv->lowerOrphan = orphan; 48062143Sarchie return (0); 48162143Sarchie} 48262143Sarchie 48362143Sarchie/* 48462143Sarchie * Receive an incoming control message. 48562143Sarchie */ 48662143Sarchiestatic int 48762143Sarchieng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 48862143Sarchie struct ng_mesg **rptr, hook_p lasthook) 48962143Sarchie{ 49062143Sarchie const priv_p priv = node->private; 49162143Sarchie struct ng_mesg *resp = NULL; 49262143Sarchie int error = 0; 49362143Sarchie 49462143Sarchie switch (msg->header.typecookie) { 49562143Sarchie case NGM_ETHER_COOKIE: 49662143Sarchie switch (msg->header.cmd) { 49762143Sarchie case NGM_ETHER_GET_IFNAME: 49862143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 49962143Sarchie if (resp == NULL) { 50062143Sarchie error = ENOMEM; 50162143Sarchie break; 50262143Sarchie } 50362143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 50462143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 50562143Sarchie break; 50662143Sarchie case NGM_ETHER_GET_IFINDEX: 50762143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 50862143Sarchie if (resp == NULL) { 50962143Sarchie error = ENOMEM; 51062143Sarchie break; 51162143Sarchie } 51262143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 51362143Sarchie break; 51464358Sarchie case NGM_ETHER_GET_ENADDR: 51564358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 51664358Sarchie if (resp == NULL) { 51764358Sarchie error = ENOMEM; 51864358Sarchie break; 51964358Sarchie } 52064358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 52164358Sarchie resp->data, ETHER_ADDR_LEN); 52264358Sarchie break; 52364653Sarchie case NGM_ETHER_SET_ENADDR: 52464653Sarchie { 52564653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 52664653Sarchie error = EINVAL; 52764653Sarchie break; 52864653Sarchie } 52964653Sarchie error = if_setlladdr(priv->ifp, 53064653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 53164653Sarchie break; 53264653Sarchie } 53364653Sarchie case NGM_ETHER_GET_PROMISC: 53464653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 53564653Sarchie if (resp == NULL) { 53664653Sarchie error = ENOMEM; 53764653Sarchie break; 53864653Sarchie } 53964653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 54064653Sarchie break; 54164358Sarchie case NGM_ETHER_SET_PROMISC: 54264358Sarchie { 54364358Sarchie u_char want; 54464358Sarchie 54564358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 54664358Sarchie error = EINVAL; 54764358Sarchie break; 54864358Sarchie } 54964358Sarchie want = !!*((u_int32_t *)msg->data); 55064358Sarchie if (want ^ priv->promisc) { 55164358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 55264358Sarchie break; 55364358Sarchie priv->promisc = want; 55464358Sarchie } 55564358Sarchie break; 55664358Sarchie } 55764653Sarchie case NGM_ETHER_GET_AUTOSRC: 55864653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 55964653Sarchie if (resp == NULL) { 56064653Sarchie error = ENOMEM; 56164653Sarchie break; 56264653Sarchie } 56364653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 56464653Sarchie break; 56564358Sarchie case NGM_ETHER_SET_AUTOSRC: 56664358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 56764358Sarchie error = EINVAL; 56864358Sarchie break; 56964358Sarchie } 57064358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 57164358Sarchie break; 57262143Sarchie default: 57362143Sarchie error = EINVAL; 57462143Sarchie break; 57562143Sarchie } 57662143Sarchie break; 57762143Sarchie default: 57862143Sarchie error = EINVAL; 57962143Sarchie break; 58062143Sarchie } 58162143Sarchie if (rptr) 58262143Sarchie *rptr = resp; 58362143Sarchie else if (resp != NULL) 58462143Sarchie FREE(resp, M_NETGRAPH); 58562143Sarchie FREE(msg, M_NETGRAPH); 58662143Sarchie return (error); 58762143Sarchie} 58862143Sarchie 58962143Sarchie/* 59062143Sarchie * Receive data on a hook. 59162143Sarchie */ 59262143Sarchiestatic int 59362143Sarchieng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 59462143Sarchie struct mbuf **ret_m, meta_p *ret_meta) 59562143Sarchie{ 59662143Sarchie const node_p node = hook->node; 59762143Sarchie const priv_p priv = node->private; 59862143Sarchie 59962143Sarchie if (hook == priv->lower) 60062143Sarchie return ng_ether_rcv_lower(node, m, meta); 60162143Sarchie if (hook == priv->upper) 60262143Sarchie return ng_ether_rcv_upper(node, m, meta); 60362143Sarchie panic("%s: weird hook", __FUNCTION__); 60462143Sarchie} 60562143Sarchie 60662143Sarchie/* 60762143Sarchie * Handle an mbuf received on the "lower" hook. 60862143Sarchie */ 60962143Sarchiestatic int 61062143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 61162143Sarchie{ 61262143Sarchie const priv_p priv = node->private; 61362143Sarchie 61462143Sarchie /* Make sure header is fully pulled up */ 61562143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 61662143Sarchie NG_FREE_DATA(m, meta); 61762143Sarchie return (EINVAL); 61862143Sarchie } 61962143Sarchie if (m->m_len < sizeof(struct ether_header) 62062143Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 62162143Sarchie NG_FREE_META(meta); 62262143Sarchie return (ENOBUFS); 62362143Sarchie } 62462143Sarchie 62564358Sarchie /* Drop in the MAC address if desired */ 62664358Sarchie if (priv->autoSrcAddr) { 62764358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 62864358Sarchie mtod(m, struct ether_header *)->ether_shost, 62964358Sarchie ETHER_ADDR_LEN); 63064358Sarchie } 63162678Sjulian 63262143Sarchie /* Send it on its way */ 63362143Sarchie NG_FREE_META(meta); 63462143Sarchie return ether_output_frame(priv->ifp, m); 63562143Sarchie} 63662143Sarchie 63762143Sarchie/* 63862143Sarchie * Handle an mbuf received on the "upper" hook. 63962143Sarchie */ 64062143Sarchiestatic int 64162143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 64262143Sarchie{ 64362143Sarchie const priv_p priv = node->private; 64462143Sarchie struct ether_header *eh; 64562143Sarchie 64662143Sarchie /* Check length and pull off header */ 64762143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 64862143Sarchie NG_FREE_DATA(m, meta); 64962143Sarchie return (EINVAL); 65062143Sarchie } 65162143Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 65262143Sarchie NG_FREE_META(meta); 65362143Sarchie return (ENOBUFS); 65462143Sarchie } 65562143Sarchie eh = mtod(m, struct ether_header *); 65662143Sarchie m->m_data += sizeof(*eh); 65762143Sarchie m->m_len -= sizeof(*eh); 65862143Sarchie m->m_pkthdr.len -= sizeof(*eh); 65966061Sjulian m->m_pkthdr.rcvif = priv->ifp; 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__); 70069840Sarchie if (hook->node->numhooks == 0) 70169840Sarchie ng_rmnode(hook->node); /* reset node */ 70262143Sarchie return (0); 70362143Sarchie} 70462143Sarchie 70564653Sarchiestatic int 70664653Sarchieng_enaddr_parse(const struct ng_parse_type *type, 70764653Sarchie const char *s, int *const off, const u_char *const start, 70864653Sarchie u_char *const buf, int *const buflen) 70964653Sarchie{ 71064653Sarchie char *eptr; 71164653Sarchie u_long val; 71264653Sarchie int i; 71364653Sarchie 71464653Sarchie if (*buflen < ETHER_ADDR_LEN) 71564653Sarchie return (ERANGE); 71664653Sarchie for (i = 0; i < ETHER_ADDR_LEN; i++) { 71764653Sarchie val = strtoul(s + *off, &eptr, 16); 71864653Sarchie if (val > 0xff || eptr == s + *off) 71964653Sarchie return (EINVAL); 72064653Sarchie buf[i] = (u_char)val; 72164653Sarchie *off = (eptr - s); 72264653Sarchie if (i < ETHER_ADDR_LEN - 1) { 72364653Sarchie if (*eptr != ':') 72464653Sarchie return (EINVAL); 72564653Sarchie (*off)++; 72664653Sarchie } 72764653Sarchie } 72864653Sarchie *buflen = ETHER_ADDR_LEN; 72964653Sarchie return (0); 73064653Sarchie} 73164653Sarchie 73264653Sarchiestatic int 73364653Sarchieng_enaddr_unparse(const struct ng_parse_type *type, 73464653Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 73564653Sarchie{ 73664653Sarchie int len; 73764653Sarchie 73864653Sarchie len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 73965305Sarchie data[*off], data[*off + 1], data[*off + 2], 74065305Sarchie data[*off + 3], data[*off + 4], data[*off + 5]); 74164653Sarchie if (len >= cbuflen) 74264653Sarchie return (ERANGE); 74364653Sarchie *off += ETHER_ADDR_LEN; 74464653Sarchie return (0); 74564653Sarchie} 74664653Sarchie 74762143Sarchie/****************************************************************** 74862143Sarchie INITIALIZATION 74962143Sarchie******************************************************************/ 75062143Sarchie 75162143Sarchie/* 75262143Sarchie * Handle loading and unloading for this node type. 75362143Sarchie */ 75462143Sarchiestatic int 75562143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 75662143Sarchie{ 75762143Sarchie struct ifnet *ifp; 75862143Sarchie int error = 0; 75962143Sarchie int s; 76062143Sarchie 76162143Sarchie s = splnet(); 76262143Sarchie switch (event) { 76362143Sarchie case MOD_LOAD: 76462143Sarchie 76562143Sarchie /* Register function hooks */ 76662143Sarchie if (ng_ether_attach_p != NULL) { 76762143Sarchie error = EEXIST; 76862143Sarchie break; 76962143Sarchie } 77062143Sarchie ng_ether_attach_p = ng_ether_attach; 77162143Sarchie ng_ether_detach_p = ng_ether_detach; 77262143Sarchie ng_ether_output_p = ng_ether_output; 77362143Sarchie ng_ether_input_p = ng_ether_input; 77462143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 77562143Sarchie 77662143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 77762143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 77862143Sarchie if (ifp->if_type == IFT_ETHER) 77962143Sarchie ng_ether_attach(ifp); 78062143Sarchie } 78162143Sarchie break; 78262143Sarchie 78362143Sarchie case MOD_UNLOAD: 78462143Sarchie 78562143Sarchie /* 78662143Sarchie * Note that the base code won't try to unload us until 78762143Sarchie * all nodes have been removed, and that can't happen 78862143Sarchie * until all Ethernet interfaces are removed. In any 78962143Sarchie * case, we know there are no nodes left if the action 79062143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 79162143Sarchie */ 79262143Sarchie 79362143Sarchie /* Unregister function hooks */ 79462143Sarchie ng_ether_attach_p = NULL; 79562143Sarchie ng_ether_detach_p = NULL; 79662143Sarchie ng_ether_output_p = NULL; 79762143Sarchie ng_ether_input_p = NULL; 79862143Sarchie ng_ether_input_orphan_p = NULL; 79962143Sarchie break; 80062143Sarchie 80162143Sarchie default: 80262143Sarchie error = EOPNOTSUPP; 80362143Sarchie break; 80462143Sarchie } 80562143Sarchie splx(s); 80662143Sarchie return (error); 80762143Sarchie} 80862143Sarchie 809