ng_ether.c revision 97896
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 97896 2002-06-05 23:32:56Z 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 */ 7890249Sarchie u_long hwassist; /* hardware checksum capabilities */ 7971849Sjulian u_int flags; /* flags e.g. really die */ 8062143Sarchie}; 8162143Sarchietypedef struct private *priv_p; 8262143Sarchie 8362143Sarchie/* Functional hooks called from if_ethersubr.c */ 8462143Sarchiestatic void ng_ether_input(struct ifnet *ifp, 8562143Sarchie struct mbuf **mp, struct ether_header *eh); 8662143Sarchiestatic void ng_ether_input_orphan(struct ifnet *ifp, 8762143Sarchie struct mbuf *m, struct ether_header *eh); 8862143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 8962143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 9062143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 9162143Sarchie 9262143Sarchie/* Other functions */ 9362143Sarchiestatic void ng_ether_input2(node_p node, 9462143Sarchie struct mbuf **mp, struct ether_header *eh); 9562143Sarchiestatic int ng_ether_glueback_header(struct mbuf **mp, 9662143Sarchie struct ether_header *eh); 9762143Sarchiestatic int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 9862143Sarchiestatic int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 9962143Sarchie 10062143Sarchie/* Netgraph node methods */ 10162143Sarchiestatic ng_constructor_t ng_ether_constructor; 10262143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 10370700Sjulianstatic ng_shutdown_t ng_ether_shutdown; 10462143Sarchiestatic ng_newhook_t ng_ether_newhook; 10569922Sjulianstatic ng_connect_t ng_ether_connect; 10662143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10762143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 10862143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 10962143Sarchie 11064653Sarchie/* Parse type for an Ethernet address */ 11164653Sarchiestatic ng_parse_t ng_enaddr_parse; 11264653Sarchiestatic ng_unparse_t ng_enaddr_unparse; 11364653Sarchieconst struct ng_parse_type ng_ether_enaddr_type = { 11464653Sarchie NULL, 11564653Sarchie NULL, 11664653Sarchie NULL, 11764653Sarchie ng_enaddr_parse, 11864653Sarchie ng_enaddr_unparse, 11964653Sarchie NULL, /* no such thing as a "default" EN address */ 12064653Sarchie 0 12164358Sarchie}; 12264358Sarchie 12362143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12462143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 12562143Sarchie { 12662143Sarchie NGM_ETHER_COOKIE, 12762143Sarchie NGM_ETHER_GET_IFNAME, 12862143Sarchie "getifname", 12962143Sarchie NULL, 13062143Sarchie &ng_parse_string_type 13162143Sarchie }, 13262143Sarchie { 13362143Sarchie NGM_ETHER_COOKIE, 13462143Sarchie NGM_ETHER_GET_IFINDEX, 13562143Sarchie "getifindex", 13662143Sarchie NULL, 13762143Sarchie &ng_parse_int32_type 13862143Sarchie }, 13964358Sarchie { 14064358Sarchie NGM_ETHER_COOKIE, 14164358Sarchie NGM_ETHER_GET_ENADDR, 14264358Sarchie "getenaddr", 14364358Sarchie NULL, 14464358Sarchie &ng_ether_enaddr_type 14564358Sarchie }, 14664358Sarchie { 14764358Sarchie NGM_ETHER_COOKIE, 14864653Sarchie NGM_ETHER_SET_ENADDR, 14964653Sarchie "setenaddr", 15064653Sarchie &ng_ether_enaddr_type, 15164653Sarchie NULL 15264653Sarchie }, 15364653Sarchie { 15464653Sarchie NGM_ETHER_COOKIE, 15564653Sarchie NGM_ETHER_GET_PROMISC, 15664653Sarchie "getpromisc", 15764653Sarchie NULL, 15864653Sarchie &ng_parse_int32_type 15964653Sarchie }, 16064653Sarchie { 16164653Sarchie NGM_ETHER_COOKIE, 16264358Sarchie NGM_ETHER_SET_PROMISC, 16364358Sarchie "setpromisc", 16464358Sarchie &ng_parse_int32_type, 16564358Sarchie NULL 16664358Sarchie }, 16764358Sarchie { 16864358Sarchie NGM_ETHER_COOKIE, 16964653Sarchie NGM_ETHER_GET_AUTOSRC, 17064653Sarchie "getautosrc", 17164653Sarchie NULL, 17264653Sarchie &ng_parse_int32_type 17364653Sarchie }, 17464653Sarchie { 17564653Sarchie NGM_ETHER_COOKIE, 17664358Sarchie NGM_ETHER_SET_AUTOSRC, 17764358Sarchie "setautosrc", 17864358Sarchie &ng_parse_int32_type, 17964358Sarchie NULL 18064358Sarchie }, 18162143Sarchie { 0 } 18262143Sarchie}; 18362143Sarchie 18462143Sarchiestatic struct ng_type ng_ether_typestruct = { 18570159Sjulian NG_ABI_VERSION, 18662143Sarchie NG_ETHER_NODE_TYPE, 18762143Sarchie ng_ether_mod_event, 18862143Sarchie ng_ether_constructor, 18962143Sarchie ng_ether_rcvmsg, 19070700Sjulian ng_ether_shutdown, 19162143Sarchie ng_ether_newhook, 19262143Sarchie NULL, 19369922Sjulian ng_ether_connect, 19462143Sarchie ng_ether_rcvdata, 19562143Sarchie ng_ether_disconnect, 19662143Sarchie ng_ether_cmdlist, 19762143Sarchie}; 19871047SjulianMODULE_VERSION(ng_ether, 1); 19962143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 20062143Sarchie 20162143Sarchie/****************************************************************** 20262143Sarchie ETHERNET FUNCTION HOOKS 20362143Sarchie******************************************************************/ 20462143Sarchie 20562143Sarchie/* 20662143Sarchie * Handle a packet that has come in on an interface. We get to 20762143Sarchie * look at it here before any upper layer protocols do. 20862143Sarchie * 20962143Sarchie * NOTE: this function will get called at splimp() 21062143Sarchie */ 21162143Sarchiestatic void 21262143Sarchieng_ether_input(struct ifnet *ifp, 21362143Sarchie struct mbuf **mp, struct ether_header *eh) 21462143Sarchie{ 21562143Sarchie const node_p node = IFP2NG(ifp); 21670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 21762143Sarchie 21862143Sarchie /* If "lower" hook not connected, let packet continue */ 21962143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 22062143Sarchie return; 22162143Sarchie ng_ether_input2(node, mp, eh); 22262143Sarchie} 22362143Sarchie 22462143Sarchie/* 22562143Sarchie * Handle a packet that has come in on an interface, and which 22662143Sarchie * does not match any of our known protocols (an ``orphan''). 22762143Sarchie * 22862143Sarchie * NOTE: this function will get called at splimp() 22962143Sarchie */ 23062143Sarchiestatic void 23162143Sarchieng_ether_input_orphan(struct ifnet *ifp, 23262143Sarchie struct mbuf *m, struct ether_header *eh) 23362143Sarchie{ 23462143Sarchie const node_p node = IFP2NG(ifp); 23570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 23662143Sarchie 23762143Sarchie /* If "orphan" hook not connected, let packet continue */ 23862143Sarchie if (priv->lower == NULL || !priv->lowerOrphan) { 23962143Sarchie m_freem(m); 24062143Sarchie return; 24162143Sarchie } 24262143Sarchie ng_ether_input2(node, &m, eh); 24362143Sarchie if (m != NULL) 24462143Sarchie m_freem(m); 24562143Sarchie} 24662143Sarchie 24762143Sarchie/* 24869922Sjulian * Handle a packet that has come in on an ethernet interface. 24962143Sarchie * The Ethernet header has already been detached from the mbuf, 25062143Sarchie * so we have to put it back. 25162143Sarchie * 25262143Sarchie * NOTE: this function will get called at splimp() 25362143Sarchie */ 25462143Sarchiestatic void 25562143Sarchieng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh) 25662143Sarchie{ 25770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 25862143Sarchie int error; 25962143Sarchie 26062143Sarchie /* Glue Ethernet header back on */ 26162143Sarchie if ((error = ng_ether_glueback_header(mp, eh)) != 0) 26262143Sarchie return; 26362143Sarchie 26462143Sarchie /* Send out lower/orphan hook */ 26569922Sjulian NG_SEND_DATA_ONLY(error, priv->lower, *mp); 26662143Sarchie *mp = NULL; 26762143Sarchie} 26862143Sarchie 26962143Sarchie/* 27062143Sarchie * Handle a packet that is going out on an interface. 27162143Sarchie * The Ethernet header is already attached to the mbuf. 27262143Sarchie */ 27362143Sarchiestatic int 27462143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 27562143Sarchie{ 27662143Sarchie const node_p node = IFP2NG(ifp); 27770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 27862143Sarchie int error = 0; 27962143Sarchie 28062143Sarchie /* If "upper" hook not connected, let packet continue */ 28162143Sarchie if (priv->upper == NULL) 28262143Sarchie return (0); 28362143Sarchie 28462143Sarchie /* Send it out "upper" hook */ 28570700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 28662143Sarchie return (error); 28762143Sarchie} 28862143Sarchie 28962143Sarchie/* 29062143Sarchie * A new Ethernet interface has been attached. 29162143Sarchie * Create a new node for it, etc. 29262143Sarchie */ 29362143Sarchiestatic void 29462143Sarchieng_ether_attach(struct ifnet *ifp) 29562143Sarchie{ 29662143Sarchie char name[IFNAMSIZ + 1]; 29762143Sarchie priv_p priv; 29862143Sarchie node_p node; 29962143Sarchie 30062143Sarchie /* Create node */ 30187599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 30262143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 30362143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 30462143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 30587599Sobrien __func__, "create node", name); 30662143Sarchie return; 30762143Sarchie } 30862143Sarchie 30962143Sarchie /* Allocate private data */ 31068876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 31162143Sarchie if (priv == NULL) { 31262143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 31387599Sobrien __func__, "allocate memory", name); 31470784Sjulian NG_NODE_UNREF(node); 31562143Sarchie return; 31662143Sarchie } 31770784Sjulian NG_NODE_SET_PRIVATE(node, priv); 31862143Sarchie priv->ifp = ifp; 31962143Sarchie IFP2NG(ifp) = node; 32064358Sarchie priv->autoSrcAddr = 1; 32190249Sarchie priv->hwassist = ifp->if_hwassist; 32262143Sarchie 32362143Sarchie /* Try to give the node the same name as the interface */ 32462143Sarchie if (ng_name_node(node, name) != 0) { 32562143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 32687599Sobrien __func__, name); 32762143Sarchie } 32862143Sarchie} 32962143Sarchie 33062143Sarchie/* 33162143Sarchie * An Ethernet interface is being detached. 33271849Sjulian * REALLY Destroy its node. 33362143Sarchie */ 33462143Sarchiestatic void 33562143Sarchieng_ether_detach(struct ifnet *ifp) 33662143Sarchie{ 33762143Sarchie const node_p node = IFP2NG(ifp); 33871849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 33962143Sarchie 34062143Sarchie if (node == NULL) /* no node (why not?), ignore */ 34162143Sarchie return; 34271849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 34371849Sjulian /* 34471849Sjulian * We can't assume the ifnet is still around when we run shutdown 34571849Sjulian * So zap it now. XXX We HOPE that anything running at this time 34671849Sjulian * handles it (as it should in the non netgraph case). 34771849Sjulian */ 34871849Sjulian IFP2NG(ifp) = NULL; 34971849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 35071849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 35162143Sarchie} 35262143Sarchie 35362143Sarchie/* 35462143Sarchie * Optimization for gluing the Ethernet header back onto 35562143Sarchie * the front of an incoming packet. 35662143Sarchie */ 35762143Sarchiestatic int 35862143Sarchieng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 35962143Sarchie{ 36062143Sarchie struct mbuf *m = *mp; 36162143Sarchie int error = 0; 36262143Sarchie 36362143Sarchie /* 36497896Sarchie * Optimize for the case where the header is already in place 36597896Sarchie * at the front of the mbuf. This is actually quite likely 36697896Sarchie * because many Ethernet drivers generate packets this way. 36762143Sarchie */ 36862143Sarchie if (eh == mtod(m, struct ether_header *) - 1) { 36962143Sarchie m->m_len += sizeof(*eh); 37062143Sarchie m->m_data -= sizeof(*eh); 37162143Sarchie m->m_pkthdr.len += sizeof(*eh); 37262143Sarchie goto done; 37362143Sarchie } 37462143Sarchie 37597896Sarchie /* Prepend the header back onto the front of the mbuf */ 37697896Sarchie M_PREPEND(m, sizeof(*eh), M_DONTWAIT); 37762143Sarchie if (m == NULL) { 37862143Sarchie error = ENOBUFS; 37962143Sarchie goto done; 38062143Sarchie } 38162143Sarchie 38297896Sarchie /* Copy header into front of mbuf */ 38397896Sarchie bcopy(eh, mtod(m, void *), sizeof(*eh)); 38497896Sarchie 38562143Sarchiedone: 38697896Sarchie /* Done */ 38762143Sarchie *mp = m; 38862143Sarchie return error; 38962143Sarchie} 39062143Sarchie 39162143Sarchie/****************************************************************** 39262143Sarchie NETGRAPH NODE METHODS 39362143Sarchie******************************************************************/ 39462143Sarchie 39562143Sarchie/* 39662143Sarchie * It is not possible or allowable to create a node of this type. 39762143Sarchie * Nodes get created when the interface is attached (or, when 39862143Sarchie * this node type's KLD is loaded). 39962143Sarchie */ 40062143Sarchiestatic int 40170700Sjulianng_ether_constructor(node_p node) 40262143Sarchie{ 40362143Sarchie return (EINVAL); 40462143Sarchie} 40562143Sarchie 40662143Sarchie/* 40762143Sarchie * Check for attaching a new hook. 40862143Sarchie */ 40962143Sarchiestatic int 41062143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 41162143Sarchie{ 41270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 41362143Sarchie u_char orphan = priv->lowerOrphan; 41462143Sarchie hook_p *hookptr; 41562143Sarchie 41662143Sarchie /* Divert hook is an alias for lower */ 41762143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 41862143Sarchie name = NG_ETHER_HOOK_LOWER; 41962143Sarchie 42062143Sarchie /* Which hook? */ 42162143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 42262143Sarchie hookptr = &priv->upper; 42362143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 42462143Sarchie hookptr = &priv->lower; 42562143Sarchie orphan = 0; 42662143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 42762143Sarchie hookptr = &priv->lower; 42862143Sarchie orphan = 1; 42962143Sarchie } else 43062143Sarchie return (EINVAL); 43162143Sarchie 43262143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 43362143Sarchie if (*hookptr != NULL) 43462143Sarchie return (EISCONN); 43562143Sarchie 43690249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 43790249Sarchie if (hookptr == &priv->upper) 43890249Sarchie priv->ifp->if_hwassist = 0; 43990249Sarchie 44062143Sarchie /* OK */ 44162143Sarchie *hookptr = hook; 44262143Sarchie priv->lowerOrphan = orphan; 44362143Sarchie return (0); 44462143Sarchie} 44562143Sarchie 44662143Sarchie/* 44769922Sjulian * Hooks are attached, adjust to force queueing. 44869922Sjulian * We don't really care which hook it is. 44969922Sjulian * they should all be queuing for outgoing data. 45069922Sjulian */ 45169922Sjulianstatic int 45269922Sjulianng_ether_connect(hook_p hook) 45369922Sjulian{ 45470784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 45569922Sjulian return (0); 45669922Sjulian} 45769922Sjulian 45869922Sjulian/* 45962143Sarchie * Receive an incoming control message. 46062143Sarchie */ 46162143Sarchiestatic int 46270700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 46362143Sarchie{ 46470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 46562143Sarchie struct ng_mesg *resp = NULL; 46662143Sarchie int error = 0; 46770700Sjulian struct ng_mesg *msg; 46862143Sarchie 46970700Sjulian NGI_GET_MSG(item, msg); 47062143Sarchie switch (msg->header.typecookie) { 47162143Sarchie case NGM_ETHER_COOKIE: 47262143Sarchie switch (msg->header.cmd) { 47362143Sarchie case NGM_ETHER_GET_IFNAME: 47462143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 47562143Sarchie if (resp == NULL) { 47662143Sarchie error = ENOMEM; 47762143Sarchie break; 47862143Sarchie } 47962143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 48062143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 48162143Sarchie break; 48262143Sarchie case NGM_ETHER_GET_IFINDEX: 48362143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 48462143Sarchie if (resp == NULL) { 48562143Sarchie error = ENOMEM; 48662143Sarchie break; 48762143Sarchie } 48862143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 48962143Sarchie break; 49064358Sarchie case NGM_ETHER_GET_ENADDR: 49164358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 49264358Sarchie if (resp == NULL) { 49364358Sarchie error = ENOMEM; 49464358Sarchie break; 49564358Sarchie } 49664358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 49764358Sarchie resp->data, ETHER_ADDR_LEN); 49864358Sarchie break; 49964653Sarchie case NGM_ETHER_SET_ENADDR: 50064653Sarchie { 50164653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 50264653Sarchie error = EINVAL; 50364653Sarchie break; 50464653Sarchie } 50564653Sarchie error = if_setlladdr(priv->ifp, 50664653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 50764653Sarchie break; 50864653Sarchie } 50964653Sarchie case NGM_ETHER_GET_PROMISC: 51064653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 51164653Sarchie if (resp == NULL) { 51264653Sarchie error = ENOMEM; 51364653Sarchie break; 51464653Sarchie } 51564653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 51664653Sarchie break; 51764358Sarchie case NGM_ETHER_SET_PROMISC: 51864358Sarchie { 51964358Sarchie u_char want; 52064358Sarchie 52164358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 52264358Sarchie error = EINVAL; 52364358Sarchie break; 52464358Sarchie } 52564358Sarchie want = !!*((u_int32_t *)msg->data); 52664358Sarchie if (want ^ priv->promisc) { 52764358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 52864358Sarchie break; 52964358Sarchie priv->promisc = want; 53064358Sarchie } 53164358Sarchie break; 53264358Sarchie } 53364653Sarchie case NGM_ETHER_GET_AUTOSRC: 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->autoSrcAddr; 54064653Sarchie break; 54164358Sarchie case NGM_ETHER_SET_AUTOSRC: 54264358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 54364358Sarchie error = EINVAL; 54464358Sarchie break; 54564358Sarchie } 54664358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 54764358Sarchie break; 54862143Sarchie default: 54962143Sarchie error = EINVAL; 55062143Sarchie break; 55162143Sarchie } 55262143Sarchie break; 55362143Sarchie default: 55462143Sarchie error = EINVAL; 55562143Sarchie break; 55662143Sarchie } 55770700Sjulian NG_RESPOND_MSG(error, node, item, resp); 55870700Sjulian NG_FREE_MSG(msg); 55962143Sarchie return (error); 56062143Sarchie} 56162143Sarchie 56262143Sarchie/* 56362143Sarchie * Receive data on a hook. 56462143Sarchie */ 56562143Sarchiestatic int 56670700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 56762143Sarchie{ 56870784Sjulian const node_p node = NG_HOOK_NODE(hook); 56970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 57070700Sjulian struct mbuf *m; 57170700Sjulian meta_p meta; 57262143Sarchie 57370700Sjulian NGI_GET_M(item, m); 57470700Sjulian NGI_GET_META(item, meta); 57570700Sjulian NG_FREE_ITEM(item); 57662143Sarchie if (hook == priv->lower) 57762143Sarchie return ng_ether_rcv_lower(node, m, meta); 57862143Sarchie if (hook == priv->upper) 57962143Sarchie return ng_ether_rcv_upper(node, m, meta); 58087599Sobrien panic("%s: weird hook", __func__); 58183366Sjulian#ifdef RESTARTABLE_PANICS /* so we don;t get an error msg in LINT */ 58283366Sjulian return NULL; 58383366Sjulian#endif 58462143Sarchie} 58562143Sarchie 58662143Sarchie/* 58762143Sarchie * Handle an mbuf received on the "lower" hook. 58862143Sarchie */ 58962143Sarchiestatic int 59062143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 59162143Sarchie{ 59270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 59396265Sarchie struct ifnet *const ifp = priv->ifp; 59462143Sarchie 59597896Sarchie /* Discard meta info */ 59697896Sarchie NG_FREE_META(meta); 59797896Sarchie 59896265Sarchie /* Check whether interface is ready for packets */ 59996265Sarchie if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 60096265Sarchie NG_FREE_M(m); 60196265Sarchie return (ENETDOWN); 60296265Sarchie } 60396265Sarchie 60462143Sarchie /* Make sure header is fully pulled up */ 60562143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 60670700Sjulian NG_FREE_M(m); 60762143Sarchie return (EINVAL); 60862143Sarchie } 60962143Sarchie if (m->m_len < sizeof(struct ether_header) 61097896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 61162143Sarchie return (ENOBUFS); 61262143Sarchie 61364358Sarchie /* Drop in the MAC address if desired */ 61464358Sarchie if (priv->autoSrcAddr) { 61597896Sarchie 61697896Sarchie /* Make the mbuf writable if it's not already */ 61797896Sarchie if (!M_WRITABLE(m) 61897896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 61997896Sarchie return (ENOBUFS); 62097896Sarchie 62197896Sarchie /* Overwrite source MAC address */ 62296265Sarchie bcopy((IFP2AC(ifp))->ac_enaddr, 62364358Sarchie mtod(m, struct ether_header *)->ether_shost, 62464358Sarchie ETHER_ADDR_LEN); 62564358Sarchie } 62662678Sjulian 62762143Sarchie /* Send it on its way */ 62896265Sarchie return ether_output_frame(ifp, m); 62962143Sarchie} 63062143Sarchie 63162143Sarchie/* 63262143Sarchie * Handle an mbuf received on the "upper" hook. 63362143Sarchie */ 63462143Sarchiestatic int 63562143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 63662143Sarchie{ 63770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 63862143Sarchie struct ether_header *eh; 63962143Sarchie 64097896Sarchie /* Discard meta info */ 64197896Sarchie NG_FREE_META(meta); 64297896Sarchie 64362143Sarchie /* Check length and pull off header */ 64462143Sarchie if (m->m_pkthdr.len < sizeof(*eh)) { 64570700Sjulian NG_FREE_M(m); 64662143Sarchie return (EINVAL); 64762143Sarchie } 64897896Sarchie if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) 64962143Sarchie return (ENOBUFS); 65062143Sarchie eh = mtod(m, struct ether_header *); 65162143Sarchie m->m_data += sizeof(*eh); 65262143Sarchie m->m_len -= sizeof(*eh); 65362143Sarchie m->m_pkthdr.len -= sizeof(*eh); 65466061Sjulian m->m_pkthdr.rcvif = priv->ifp; 65562143Sarchie 65662143Sarchie /* Route packet back in */ 65762143Sarchie ether_demux(priv->ifp, eh, m); 65862143Sarchie return (0); 65962143Sarchie} 66062143Sarchie 66162143Sarchie/* 66271849Sjulian * Shutdown node. This resets the node but does not remove it 66371849Sjulian * unless the REALLY_DIE flag is set. 66462143Sarchie */ 66562143Sarchiestatic int 66670700Sjulianng_ether_shutdown(node_p node) 66762143Sarchie{ 66870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 66964358Sarchie 67064358Sarchie if (priv->promisc) { /* disable promiscuous mode */ 67164358Sarchie (void)ifpromisc(priv->ifp, 0); 67264358Sarchie priv->promisc = 0; 67364358Sarchie } 67471849Sjulian if (node->nd_flags & NG_REALLY_DIE) { 67571849Sjulian /* 67671849Sjulian * WE came here because the ethernet card is being unloaded, 67771849Sjulian * so stop being persistant. 67871849Sjulian * Actually undo all the things we did on creation. 67971849Sjulian * Assume the ifp has already been freed. 68071849Sjulian */ 68171849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 68271849Sjulian FREE(priv, M_NETGRAPH); 68371849Sjulian NG_NODE_UNREF(node); /* free node itself */ 68471849Sjulian return (0); 68570700Sjulian } 68664358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 68771849Sjulian node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */ 68862143Sarchie return (0); 68962143Sarchie} 69062143Sarchie 69162143Sarchie/* 69262143Sarchie * Hook disconnection. 69362143Sarchie */ 69462143Sarchiestatic int 69562143Sarchieng_ether_disconnect(hook_p hook) 69662143Sarchie{ 69770784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 69862143Sarchie 69990249Sarchie if (hook == priv->upper) { 70062143Sarchie priv->upper = NULL; 70190249Sarchie priv->ifp->if_hwassist = priv->hwassist; /* restore h/w csum */ 70290249Sarchie } else if (hook == priv->lower) { 70362143Sarchie priv->lower = NULL; 70462143Sarchie priv->lowerOrphan = 0; 70562143Sarchie } else 70687599Sobrien panic("%s: weird hook", __func__); 70770784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 70870784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 70970784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 71062143Sarchie return (0); 71162143Sarchie} 71262143Sarchie 71364653Sarchiestatic int 71464653Sarchieng_enaddr_parse(const struct ng_parse_type *type, 71564653Sarchie const char *s, int *const off, const u_char *const start, 71664653Sarchie u_char *const buf, int *const buflen) 71764653Sarchie{ 71864653Sarchie char *eptr; 71964653Sarchie u_long val; 72064653Sarchie int i; 72164653Sarchie 72264653Sarchie if (*buflen < ETHER_ADDR_LEN) 72364653Sarchie return (ERANGE); 72464653Sarchie for (i = 0; i < ETHER_ADDR_LEN; i++) { 72564653Sarchie val = strtoul(s + *off, &eptr, 16); 72664653Sarchie if (val > 0xff || eptr == s + *off) 72764653Sarchie return (EINVAL); 72864653Sarchie buf[i] = (u_char)val; 72964653Sarchie *off = (eptr - s); 73064653Sarchie if (i < ETHER_ADDR_LEN - 1) { 73164653Sarchie if (*eptr != ':') 73264653Sarchie return (EINVAL); 73364653Sarchie (*off)++; 73464653Sarchie } 73564653Sarchie } 73664653Sarchie *buflen = ETHER_ADDR_LEN; 73764653Sarchie return (0); 73864653Sarchie} 73964653Sarchie 74064653Sarchiestatic int 74164653Sarchieng_enaddr_unparse(const struct ng_parse_type *type, 74264653Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 74364653Sarchie{ 74464653Sarchie int len; 74564653Sarchie 74664653Sarchie len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 74765305Sarchie data[*off], data[*off + 1], data[*off + 2], 74865305Sarchie data[*off + 3], data[*off + 4], data[*off + 5]); 74964653Sarchie if (len >= cbuflen) 75064653Sarchie return (ERANGE); 75164653Sarchie *off += ETHER_ADDR_LEN; 75264653Sarchie return (0); 75364653Sarchie} 75464653Sarchie 75562143Sarchie/****************************************************************** 75662143Sarchie INITIALIZATION 75762143Sarchie******************************************************************/ 75862143Sarchie 75962143Sarchie/* 76062143Sarchie * Handle loading and unloading for this node type. 76162143Sarchie */ 76262143Sarchiestatic int 76362143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 76462143Sarchie{ 76562143Sarchie struct ifnet *ifp; 76662143Sarchie int error = 0; 76762143Sarchie int s; 76862143Sarchie 76962143Sarchie s = splnet(); 77062143Sarchie switch (event) { 77162143Sarchie case MOD_LOAD: 77262143Sarchie 77362143Sarchie /* Register function hooks */ 77462143Sarchie if (ng_ether_attach_p != NULL) { 77562143Sarchie error = EEXIST; 77662143Sarchie break; 77762143Sarchie } 77862143Sarchie ng_ether_attach_p = ng_ether_attach; 77962143Sarchie ng_ether_detach_p = ng_ether_detach; 78062143Sarchie ng_ether_output_p = ng_ether_output; 78162143Sarchie ng_ether_input_p = ng_ether_input; 78262143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 78362143Sarchie 78462143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 78562143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 78682586Sarchie if (ifp->if_type == IFT_ETHER 78782586Sarchie || ifp->if_type == IFT_L2VLAN) 78862143Sarchie ng_ether_attach(ifp); 78962143Sarchie } 79062143Sarchie break; 79162143Sarchie 79262143Sarchie case MOD_UNLOAD: 79362143Sarchie 79462143Sarchie /* 79562143Sarchie * Note that the base code won't try to unload us until 79662143Sarchie * all nodes have been removed, and that can't happen 79762143Sarchie * until all Ethernet interfaces are removed. In any 79862143Sarchie * case, we know there are no nodes left if the action 79962143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 80062143Sarchie */ 80162143Sarchie 80262143Sarchie /* Unregister function hooks */ 80362143Sarchie ng_ether_attach_p = NULL; 80462143Sarchie ng_ether_detach_p = NULL; 80562143Sarchie ng_ether_output_p = NULL; 80662143Sarchie ng_ether_input_p = NULL; 80762143Sarchie ng_ether_input_orphan_p = NULL; 80862143Sarchie break; 80962143Sarchie 81062143Sarchie default: 81162143Sarchie error = EOPNOTSUPP; 81262143Sarchie break; 81362143Sarchie } 81462143Sarchie splx(s); 81562143Sarchie return (error); 81662143Sarchie} 81762143Sarchie 818