ng_ether.c revision 126035
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 126035 2004-02-20 08:26:27Z pjd $ 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 70126035Spjd/* Per-node private data */ 71126035Spjdstruct private { 72126035Spjd struct ifnet *ifp; /* associated interface */ 73126035Spjd hook_p upper; /* upper hook connection */ 74126035Spjd hook_p lower; /* lower OR orphan hook connection */ 75126035Spjd u_char lowerOrphan; /* whether lower is lower or orphan */ 76126035Spjd u_char autoSrcAddr; /* always overwrite source address */ 77126035Spjd u_char promisc; /* promiscuous mode enabled */ 78126035Spjd u_long hwassist; /* hardware checksum capabilities */ 79126035Spjd u_int flags; /* flags e.g. really die */ 80126035Spjd}; 81126035Spjdtypedef struct private *priv_p; 8262143Sarchie 83106933Ssam/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 84106933Ssamextern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 85106933Ssamextern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 86106933Ssamextern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 87106933Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 88106933Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 89106933Ssam 9062143Sarchie/* Functional hooks called from if_ethersubr.c */ 91106933Ssamstatic void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 92106933Ssamstatic void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 9362143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 9462143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 9562143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 9662143Sarchie 9762143Sarchie/* Other functions */ 98106933Ssamstatic void ng_ether_input2(node_p node, struct mbuf **mp); 9962143Sarchiestatic int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 10062143Sarchiestatic int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 10162143Sarchie 10262143Sarchie/* Netgraph node methods */ 10362143Sarchiestatic ng_constructor_t ng_ether_constructor; 10462143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 10570700Sjulianstatic ng_shutdown_t ng_ether_shutdown; 10662143Sarchiestatic ng_newhook_t ng_ether_newhook; 10769922Sjulianstatic ng_connect_t ng_ether_connect; 10862143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 10962143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 11062143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 11162143Sarchie 11262143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 11362143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 11462143Sarchie { 11562143Sarchie NGM_ETHER_COOKIE, 11662143Sarchie NGM_ETHER_GET_IFNAME, 11762143Sarchie "getifname", 11862143Sarchie NULL, 11962143Sarchie &ng_parse_string_type 12062143Sarchie }, 12162143Sarchie { 12262143Sarchie NGM_ETHER_COOKIE, 12362143Sarchie NGM_ETHER_GET_IFINDEX, 12462143Sarchie "getifindex", 12562143Sarchie NULL, 12662143Sarchie &ng_parse_int32_type 12762143Sarchie }, 12864358Sarchie { 12964358Sarchie NGM_ETHER_COOKIE, 13064358Sarchie NGM_ETHER_GET_ENADDR, 13164358Sarchie "getenaddr", 13264358Sarchie NULL, 133123600Sru &ng_parse_enaddr_type 13464358Sarchie }, 13564358Sarchie { 13664358Sarchie NGM_ETHER_COOKIE, 13764653Sarchie NGM_ETHER_SET_ENADDR, 13864653Sarchie "setenaddr", 139123600Sru &ng_parse_enaddr_type, 14064653Sarchie NULL 14164653Sarchie }, 14264653Sarchie { 14364653Sarchie NGM_ETHER_COOKIE, 14464653Sarchie NGM_ETHER_GET_PROMISC, 14564653Sarchie "getpromisc", 14664653Sarchie NULL, 14764653Sarchie &ng_parse_int32_type 14864653Sarchie }, 14964653Sarchie { 15064653Sarchie NGM_ETHER_COOKIE, 15164358Sarchie NGM_ETHER_SET_PROMISC, 15264358Sarchie "setpromisc", 15364358Sarchie &ng_parse_int32_type, 15464358Sarchie NULL 15564358Sarchie }, 15664358Sarchie { 15764358Sarchie NGM_ETHER_COOKIE, 15864653Sarchie NGM_ETHER_GET_AUTOSRC, 15964653Sarchie "getautosrc", 16064653Sarchie NULL, 16164653Sarchie &ng_parse_int32_type 16264653Sarchie }, 16364653Sarchie { 16464653Sarchie NGM_ETHER_COOKIE, 16564358Sarchie NGM_ETHER_SET_AUTOSRC, 16664358Sarchie "setautosrc", 16764358Sarchie &ng_parse_int32_type, 16864358Sarchie NULL 16964358Sarchie }, 17062143Sarchie { 0 } 17162143Sarchie}; 17262143Sarchie 17362143Sarchiestatic struct ng_type ng_ether_typestruct = { 17470159Sjulian NG_ABI_VERSION, 17562143Sarchie NG_ETHER_NODE_TYPE, 17662143Sarchie ng_ether_mod_event, 17762143Sarchie ng_ether_constructor, 17862143Sarchie ng_ether_rcvmsg, 17970700Sjulian ng_ether_shutdown, 18062143Sarchie ng_ether_newhook, 18162143Sarchie NULL, 18269922Sjulian ng_ether_connect, 18362143Sarchie ng_ether_rcvdata, 18462143Sarchie ng_ether_disconnect, 18562143Sarchie ng_ether_cmdlist, 18662143Sarchie}; 18771047SjulianMODULE_VERSION(ng_ether, 1); 18862143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 18962143Sarchie 19062143Sarchie/****************************************************************** 19162143Sarchie ETHERNET FUNCTION HOOKS 19262143Sarchie******************************************************************/ 19362143Sarchie 19462143Sarchie/* 19562143Sarchie * Handle a packet that has come in on an interface. We get to 19662143Sarchie * look at it here before any upper layer protocols do. 19762143Sarchie * 19862143Sarchie * NOTE: this function will get called at splimp() 19962143Sarchie */ 20062143Sarchiestatic void 201106933Ssamng_ether_input(struct ifnet *ifp, struct mbuf **mp) 20262143Sarchie{ 20362143Sarchie const node_p node = IFP2NG(ifp); 20470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 20562143Sarchie 20662143Sarchie /* If "lower" hook not connected, let packet continue */ 20762143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 20862143Sarchie return; 209106933Ssam ng_ether_input2(node, mp); 21062143Sarchie} 21162143Sarchie 21262143Sarchie/* 21362143Sarchie * Handle a packet that has come in on an interface, and which 21462143Sarchie * does not match any of our known protocols (an ``orphan''). 21562143Sarchie * 21662143Sarchie * NOTE: this function will get called at splimp() 21762143Sarchie */ 21862143Sarchiestatic void 219106933Ssamng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 22062143Sarchie{ 22162143Sarchie const node_p node = IFP2NG(ifp); 22270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 22362143Sarchie 22462143Sarchie /* If "orphan" hook not connected, let packet continue */ 22562143Sarchie if (priv->lower == NULL || !priv->lowerOrphan) { 22662143Sarchie m_freem(m); 22762143Sarchie return; 22862143Sarchie } 229106933Ssam ng_ether_input2(node, &m); 23062143Sarchie if (m != NULL) 23162143Sarchie m_freem(m); 23262143Sarchie} 23362143Sarchie 23462143Sarchie/* 23569922Sjulian * Handle a packet that has come in on an ethernet interface. 23662143Sarchie * The Ethernet header has already been detached from the mbuf, 23762143Sarchie * so we have to put it back. 23862143Sarchie * 23962143Sarchie * NOTE: this function will get called at splimp() 24062143Sarchie */ 24162143Sarchiestatic void 242106933Ssamng_ether_input2(node_p node, struct mbuf **mp) 24362143Sarchie{ 24470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 24562143Sarchie int error; 24662143Sarchie 24762143Sarchie /* Send out lower/orphan hook */ 24869922Sjulian NG_SEND_DATA_ONLY(error, priv->lower, *mp); 24962143Sarchie *mp = NULL; 25062143Sarchie} 25162143Sarchie 25262143Sarchie/* 25362143Sarchie * Handle a packet that is going out on an interface. 25462143Sarchie * The Ethernet header is already attached to the mbuf. 25562143Sarchie */ 25662143Sarchiestatic int 25762143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 25862143Sarchie{ 25962143Sarchie const node_p node = IFP2NG(ifp); 26070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 26162143Sarchie int error = 0; 26262143Sarchie 26362143Sarchie /* If "upper" hook not connected, let packet continue */ 26462143Sarchie if (priv->upper == NULL) 26562143Sarchie return (0); 26662143Sarchie 26762143Sarchie /* Send it out "upper" hook */ 26870700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 26962143Sarchie return (error); 27062143Sarchie} 27162143Sarchie 27262143Sarchie/* 27362143Sarchie * A new Ethernet interface has been attached. 27462143Sarchie * Create a new node for it, etc. 27562143Sarchie */ 27662143Sarchiestatic void 27762143Sarchieng_ether_attach(struct ifnet *ifp) 27862143Sarchie{ 27962143Sarchie priv_p priv; 28062143Sarchie node_p node; 28162143Sarchie 28262143Sarchie /* Create node */ 28387599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 28462143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 28562143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 286121816Sbrooks __func__, "create node", ifp->if_xname); 28762143Sarchie return; 28862143Sarchie } 28962143Sarchie 29062143Sarchie /* Allocate private data */ 29168876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 29262143Sarchie if (priv == NULL) { 29362143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 294121816Sbrooks __func__, "allocate memory", ifp->if_xname); 29570784Sjulian NG_NODE_UNREF(node); 29662143Sarchie return; 29762143Sarchie } 29870784Sjulian NG_NODE_SET_PRIVATE(node, priv); 29962143Sarchie priv->ifp = ifp; 30062143Sarchie IFP2NG(ifp) = node; 30164358Sarchie priv->autoSrcAddr = 1; 30290249Sarchie priv->hwassist = ifp->if_hwassist; 30362143Sarchie 30462143Sarchie /* Try to give the node the same name as the interface */ 305121816Sbrooks if (ng_name_node(node, ifp->if_xname) != 0) { 30662143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 307121816Sbrooks __func__, ifp->if_xname); 30862143Sarchie } 30962143Sarchie} 31062143Sarchie 31162143Sarchie/* 31262143Sarchie * An Ethernet interface is being detached. 31371849Sjulian * REALLY Destroy its node. 31462143Sarchie */ 31562143Sarchiestatic void 31662143Sarchieng_ether_detach(struct ifnet *ifp) 31762143Sarchie{ 31862143Sarchie const node_p node = IFP2NG(ifp); 31971849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 32062143Sarchie 32162143Sarchie if (node == NULL) /* no node (why not?), ignore */ 32262143Sarchie return; 32371849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 32471849Sjulian /* 32571849Sjulian * We can't assume the ifnet is still around when we run shutdown 32671849Sjulian * So zap it now. XXX We HOPE that anything running at this time 32771849Sjulian * handles it (as it should in the non netgraph case). 32871849Sjulian */ 32971849Sjulian IFP2NG(ifp) = NULL; 33071849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 33171849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 33262143Sarchie} 33362143Sarchie 33462143Sarchie/****************************************************************** 33562143Sarchie NETGRAPH NODE METHODS 33662143Sarchie******************************************************************/ 33762143Sarchie 33862143Sarchie/* 33962143Sarchie * It is not possible or allowable to create a node of this type. 34062143Sarchie * Nodes get created when the interface is attached (or, when 34162143Sarchie * this node type's KLD is loaded). 34262143Sarchie */ 34362143Sarchiestatic int 34470700Sjulianng_ether_constructor(node_p node) 34562143Sarchie{ 34662143Sarchie return (EINVAL); 34762143Sarchie} 34862143Sarchie 34962143Sarchie/* 35062143Sarchie * Check for attaching a new hook. 35162143Sarchie */ 35262143Sarchiestatic int 35362143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 35462143Sarchie{ 35570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 35662143Sarchie u_char orphan = priv->lowerOrphan; 35762143Sarchie hook_p *hookptr; 35862143Sarchie 35962143Sarchie /* Divert hook is an alias for lower */ 36062143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 36162143Sarchie name = NG_ETHER_HOOK_LOWER; 36262143Sarchie 36362143Sarchie /* Which hook? */ 36462143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 36562143Sarchie hookptr = &priv->upper; 36662143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 36762143Sarchie hookptr = &priv->lower; 36862143Sarchie orphan = 0; 36962143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 37062143Sarchie hookptr = &priv->lower; 37162143Sarchie orphan = 1; 37262143Sarchie } else 37362143Sarchie return (EINVAL); 37462143Sarchie 37562143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 37662143Sarchie if (*hookptr != NULL) 37762143Sarchie return (EISCONN); 37862143Sarchie 37990249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 38090249Sarchie if (hookptr == &priv->upper) 38190249Sarchie priv->ifp->if_hwassist = 0; 38290249Sarchie 38362143Sarchie /* OK */ 38462143Sarchie *hookptr = hook; 38562143Sarchie priv->lowerOrphan = orphan; 38662143Sarchie return (0); 38762143Sarchie} 38862143Sarchie 38962143Sarchie/* 39069922Sjulian * Hooks are attached, adjust to force queueing. 39169922Sjulian * We don't really care which hook it is. 39269922Sjulian * they should all be queuing for outgoing data. 39369922Sjulian */ 39469922Sjulianstatic int 39569922Sjulianng_ether_connect(hook_p hook) 39669922Sjulian{ 39770784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 39869922Sjulian return (0); 39969922Sjulian} 40069922Sjulian 40169922Sjulian/* 40262143Sarchie * Receive an incoming control message. 40362143Sarchie */ 40462143Sarchiestatic int 40570700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 40662143Sarchie{ 40770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 40862143Sarchie struct ng_mesg *resp = NULL; 40962143Sarchie int error = 0; 41070700Sjulian struct ng_mesg *msg; 41162143Sarchie 41270700Sjulian NGI_GET_MSG(item, msg); 41362143Sarchie switch (msg->header.typecookie) { 41462143Sarchie case NGM_ETHER_COOKIE: 41562143Sarchie switch (msg->header.cmd) { 41662143Sarchie case NGM_ETHER_GET_IFNAME: 41762143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 41862143Sarchie if (resp == NULL) { 41962143Sarchie error = ENOMEM; 42062143Sarchie break; 42162143Sarchie } 422121816Sbrooks strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1); 42362143Sarchie break; 42462143Sarchie case NGM_ETHER_GET_IFINDEX: 42562143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 42662143Sarchie if (resp == NULL) { 42762143Sarchie error = ENOMEM; 42862143Sarchie break; 42962143Sarchie } 43062143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 43162143Sarchie break; 43264358Sarchie case NGM_ETHER_GET_ENADDR: 43364358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 43464358Sarchie if (resp == NULL) { 43564358Sarchie error = ENOMEM; 43664358Sarchie break; 43764358Sarchie } 43864358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 43964358Sarchie resp->data, ETHER_ADDR_LEN); 44064358Sarchie break; 44164653Sarchie case NGM_ETHER_SET_ENADDR: 44264653Sarchie { 44364653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 44464653Sarchie error = EINVAL; 44564653Sarchie break; 44664653Sarchie } 44764653Sarchie error = if_setlladdr(priv->ifp, 44864653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 44964653Sarchie break; 45064653Sarchie } 45164653Sarchie case NGM_ETHER_GET_PROMISC: 45264653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 45364653Sarchie if (resp == NULL) { 45464653Sarchie error = ENOMEM; 45564653Sarchie break; 45664653Sarchie } 45764653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 45864653Sarchie break; 45964358Sarchie case NGM_ETHER_SET_PROMISC: 46064358Sarchie { 46164358Sarchie u_char want; 46264358Sarchie 46364358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 46464358Sarchie error = EINVAL; 46564358Sarchie break; 46664358Sarchie } 46764358Sarchie want = !!*((u_int32_t *)msg->data); 46864358Sarchie if (want ^ priv->promisc) { 46964358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 47064358Sarchie break; 47164358Sarchie priv->promisc = want; 47264358Sarchie } 47364358Sarchie break; 47464358Sarchie } 47564653Sarchie case NGM_ETHER_GET_AUTOSRC: 47664653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 47764653Sarchie if (resp == NULL) { 47864653Sarchie error = ENOMEM; 47964653Sarchie break; 48064653Sarchie } 48164653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 48264653Sarchie break; 48364358Sarchie case NGM_ETHER_SET_AUTOSRC: 48464358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 48564358Sarchie error = EINVAL; 48664358Sarchie break; 48764358Sarchie } 48864358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 48964358Sarchie break; 49062143Sarchie default: 49162143Sarchie error = EINVAL; 49262143Sarchie break; 49362143Sarchie } 49462143Sarchie break; 49562143Sarchie default: 49662143Sarchie error = EINVAL; 49762143Sarchie break; 49862143Sarchie } 49970700Sjulian NG_RESPOND_MSG(error, node, item, resp); 50070700Sjulian NG_FREE_MSG(msg); 50162143Sarchie return (error); 50262143Sarchie} 50362143Sarchie 50462143Sarchie/* 50562143Sarchie * Receive data on a hook. 50662143Sarchie */ 50762143Sarchiestatic int 50870700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 50962143Sarchie{ 51070784Sjulian const node_p node = NG_HOOK_NODE(hook); 51170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 51270700Sjulian struct mbuf *m; 51370700Sjulian meta_p meta; 51462143Sarchie 51570700Sjulian NGI_GET_M(item, m); 51670700Sjulian NGI_GET_META(item, meta); 51770700Sjulian NG_FREE_ITEM(item); 51862143Sarchie if (hook == priv->lower) 51962143Sarchie return ng_ether_rcv_lower(node, m, meta); 52062143Sarchie if (hook == priv->upper) 52162143Sarchie return ng_ether_rcv_upper(node, m, meta); 52287599Sobrien panic("%s: weird hook", __func__); 52383366Sjulian#ifdef RESTARTABLE_PANICS /* so we don;t get an error msg in LINT */ 52483366Sjulian return NULL; 52583366Sjulian#endif 52662143Sarchie} 52762143Sarchie 52862143Sarchie/* 52962143Sarchie * Handle an mbuf received on the "lower" hook. 53062143Sarchie */ 53162143Sarchiestatic int 53262143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 53362143Sarchie{ 53470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 53596265Sarchie struct ifnet *const ifp = priv->ifp; 53662143Sarchie 53797896Sarchie /* Discard meta info */ 53897896Sarchie NG_FREE_META(meta); 53997896Sarchie 54096265Sarchie /* Check whether interface is ready for packets */ 54196265Sarchie if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 54296265Sarchie NG_FREE_M(m); 54396265Sarchie return (ENETDOWN); 54496265Sarchie } 54596265Sarchie 54662143Sarchie /* Make sure header is fully pulled up */ 54762143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 54870700Sjulian NG_FREE_M(m); 54962143Sarchie return (EINVAL); 55062143Sarchie } 55162143Sarchie if (m->m_len < sizeof(struct ether_header) 55297896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 55362143Sarchie return (ENOBUFS); 55462143Sarchie 55564358Sarchie /* Drop in the MAC address if desired */ 55664358Sarchie if (priv->autoSrcAddr) { 55797896Sarchie 55897896Sarchie /* Make the mbuf writable if it's not already */ 55997896Sarchie if (!M_WRITABLE(m) 56097896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 56197896Sarchie return (ENOBUFS); 56297896Sarchie 56397896Sarchie /* Overwrite source MAC address */ 56496265Sarchie bcopy((IFP2AC(ifp))->ac_enaddr, 56564358Sarchie mtod(m, struct ether_header *)->ether_shost, 56664358Sarchie ETHER_ADDR_LEN); 56764358Sarchie } 56862678Sjulian 56962143Sarchie /* Send it on its way */ 57096265Sarchie return ether_output_frame(ifp, m); 57162143Sarchie} 57262143Sarchie 57362143Sarchie/* 57462143Sarchie * Handle an mbuf received on the "upper" hook. 57562143Sarchie */ 57662143Sarchiestatic int 57762143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 57862143Sarchie{ 57970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 58062143Sarchie 58197896Sarchie /* Discard meta info */ 58297896Sarchie NG_FREE_META(meta); 58397896Sarchie 58466061Sjulian m->m_pkthdr.rcvif = priv->ifp; 58562143Sarchie 58662143Sarchie /* Route packet back in */ 587106933Ssam ether_demux(priv->ifp, m); 58862143Sarchie return (0); 58962143Sarchie} 59062143Sarchie 59162143Sarchie/* 59271849Sjulian * Shutdown node. This resets the node but does not remove it 59371849Sjulian * unless the REALLY_DIE flag is set. 59462143Sarchie */ 59562143Sarchiestatic int 59670700Sjulianng_ether_shutdown(node_p node) 59762143Sarchie{ 59870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 59964358Sarchie 60071849Sjulian if (node->nd_flags & NG_REALLY_DIE) { 60171849Sjulian /* 60271849Sjulian * WE came here because the ethernet card is being unloaded, 60371849Sjulian * so stop being persistant. 60471849Sjulian * Actually undo all the things we did on creation. 60571849Sjulian * Assume the ifp has already been freed. 60671849Sjulian */ 60771849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 60871849Sjulian FREE(priv, M_NETGRAPH); 60971849Sjulian NG_NODE_UNREF(node); /* free node itself */ 61071849Sjulian return (0); 61170700Sjulian } 612124269Sgreen if (priv->promisc) { /* disable promiscuous mode */ 613124269Sgreen (void)ifpromisc(priv->ifp, 0); 614124269Sgreen priv->promisc = 0; 615124269Sgreen } 61664358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 61771849Sjulian node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */ 61862143Sarchie return (0); 61962143Sarchie} 62062143Sarchie 62162143Sarchie/* 62262143Sarchie * Hook disconnection. 62362143Sarchie */ 62462143Sarchiestatic int 62562143Sarchieng_ether_disconnect(hook_p hook) 62662143Sarchie{ 62770784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 62862143Sarchie 62990249Sarchie if (hook == priv->upper) { 63062143Sarchie priv->upper = NULL; 631124270Sgreen if (priv->ifp != NULL) /* restore h/w csum */ 632124270Sgreen priv->ifp->if_hwassist = priv->hwassist; 63390249Sarchie } else if (hook == priv->lower) { 63462143Sarchie priv->lower = NULL; 63562143Sarchie priv->lowerOrphan = 0; 63662143Sarchie } else 63787599Sobrien panic("%s: weird hook", __func__); 63870784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 63970784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 64070784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 64162143Sarchie return (0); 64262143Sarchie} 64362143Sarchie 64462143Sarchie/****************************************************************** 64562143Sarchie INITIALIZATION 64662143Sarchie******************************************************************/ 64762143Sarchie 64862143Sarchie/* 64962143Sarchie * Handle loading and unloading for this node type. 65062143Sarchie */ 65162143Sarchiestatic int 65262143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 65362143Sarchie{ 65462143Sarchie struct ifnet *ifp; 65562143Sarchie int error = 0; 65662143Sarchie int s; 65762143Sarchie 65862143Sarchie s = splnet(); 65962143Sarchie switch (event) { 66062143Sarchie case MOD_LOAD: 66162143Sarchie 66262143Sarchie /* Register function hooks */ 66362143Sarchie if (ng_ether_attach_p != NULL) { 66462143Sarchie error = EEXIST; 66562143Sarchie break; 66662143Sarchie } 66762143Sarchie ng_ether_attach_p = ng_ether_attach; 66862143Sarchie ng_ether_detach_p = ng_ether_detach; 66962143Sarchie ng_ether_output_p = ng_ether_output; 67062143Sarchie ng_ether_input_p = ng_ether_input; 67162143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 67262143Sarchie 67362143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 674108172Shsu IFNET_RLOCK(); 67562143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 67682586Sarchie if (ifp->if_type == IFT_ETHER 67782586Sarchie || ifp->if_type == IFT_L2VLAN) 67862143Sarchie ng_ether_attach(ifp); 67962143Sarchie } 680108172Shsu IFNET_RUNLOCK(); 68162143Sarchie break; 68262143Sarchie 68362143Sarchie case MOD_UNLOAD: 68462143Sarchie 68562143Sarchie /* 68662143Sarchie * Note that the base code won't try to unload us until 68762143Sarchie * all nodes have been removed, and that can't happen 68862143Sarchie * until all Ethernet interfaces are removed. In any 68962143Sarchie * case, we know there are no nodes left if the action 69062143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 69162143Sarchie */ 69262143Sarchie 69362143Sarchie /* Unregister function hooks */ 69462143Sarchie ng_ether_attach_p = NULL; 69562143Sarchie ng_ether_detach_p = NULL; 69662143Sarchie ng_ether_output_p = NULL; 69762143Sarchie ng_ether_input_p = NULL; 69862143Sarchie ng_ether_input_orphan_p = NULL; 69962143Sarchie break; 70062143Sarchie 70162143Sarchie default: 70262143Sarchie error = EOPNOTSUPP; 70362143Sarchie break; 70462143Sarchie } 70562143Sarchie splx(s); 70662143Sarchie return (error); 70762143Sarchie} 70862143Sarchie 709