ng_ether.c revision 106933
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 106933 2002-11-14 23:44:37Z sam $ 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 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 11264653Sarchie/* Parse type for an Ethernet address */ 11364653Sarchiestatic ng_parse_t ng_enaddr_parse; 11464653Sarchiestatic ng_unparse_t ng_enaddr_unparse; 11564653Sarchieconst struct ng_parse_type ng_ether_enaddr_type = { 11664653Sarchie NULL, 11764653Sarchie NULL, 11864653Sarchie NULL, 11964653Sarchie ng_enaddr_parse, 12064653Sarchie ng_enaddr_unparse, 12164653Sarchie NULL, /* no such thing as a "default" EN address */ 12264653Sarchie 0 12364358Sarchie}; 12464358Sarchie 12562143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12662143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 12762143Sarchie { 12862143Sarchie NGM_ETHER_COOKIE, 12962143Sarchie NGM_ETHER_GET_IFNAME, 13062143Sarchie "getifname", 13162143Sarchie NULL, 13262143Sarchie &ng_parse_string_type 13362143Sarchie }, 13462143Sarchie { 13562143Sarchie NGM_ETHER_COOKIE, 13662143Sarchie NGM_ETHER_GET_IFINDEX, 13762143Sarchie "getifindex", 13862143Sarchie NULL, 13962143Sarchie &ng_parse_int32_type 14062143Sarchie }, 14164358Sarchie { 14264358Sarchie NGM_ETHER_COOKIE, 14364358Sarchie NGM_ETHER_GET_ENADDR, 14464358Sarchie "getenaddr", 14564358Sarchie NULL, 14664358Sarchie &ng_ether_enaddr_type 14764358Sarchie }, 14864358Sarchie { 14964358Sarchie NGM_ETHER_COOKIE, 15064653Sarchie NGM_ETHER_SET_ENADDR, 15164653Sarchie "setenaddr", 15264653Sarchie &ng_ether_enaddr_type, 15364653Sarchie NULL 15464653Sarchie }, 15564653Sarchie { 15664653Sarchie NGM_ETHER_COOKIE, 15764653Sarchie NGM_ETHER_GET_PROMISC, 15864653Sarchie "getpromisc", 15964653Sarchie NULL, 16064653Sarchie &ng_parse_int32_type 16164653Sarchie }, 16264653Sarchie { 16364653Sarchie NGM_ETHER_COOKIE, 16464358Sarchie NGM_ETHER_SET_PROMISC, 16564358Sarchie "setpromisc", 16664358Sarchie &ng_parse_int32_type, 16764358Sarchie NULL 16864358Sarchie }, 16964358Sarchie { 17064358Sarchie NGM_ETHER_COOKIE, 17164653Sarchie NGM_ETHER_GET_AUTOSRC, 17264653Sarchie "getautosrc", 17364653Sarchie NULL, 17464653Sarchie &ng_parse_int32_type 17564653Sarchie }, 17664653Sarchie { 17764653Sarchie NGM_ETHER_COOKIE, 17864358Sarchie NGM_ETHER_SET_AUTOSRC, 17964358Sarchie "setautosrc", 18064358Sarchie &ng_parse_int32_type, 18164358Sarchie NULL 18264358Sarchie }, 18362143Sarchie { 0 } 18462143Sarchie}; 18562143Sarchie 18662143Sarchiestatic struct ng_type ng_ether_typestruct = { 18770159Sjulian NG_ABI_VERSION, 18862143Sarchie NG_ETHER_NODE_TYPE, 18962143Sarchie ng_ether_mod_event, 19062143Sarchie ng_ether_constructor, 19162143Sarchie ng_ether_rcvmsg, 19270700Sjulian ng_ether_shutdown, 19362143Sarchie ng_ether_newhook, 19462143Sarchie NULL, 19569922Sjulian ng_ether_connect, 19662143Sarchie ng_ether_rcvdata, 19762143Sarchie ng_ether_disconnect, 19862143Sarchie ng_ether_cmdlist, 19962143Sarchie}; 20071047SjulianMODULE_VERSION(ng_ether, 1); 20162143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 20262143Sarchie 20362143Sarchie/****************************************************************** 20462143Sarchie ETHERNET FUNCTION HOOKS 20562143Sarchie******************************************************************/ 20662143Sarchie 20762143Sarchie/* 20862143Sarchie * Handle a packet that has come in on an interface. We get to 20962143Sarchie * look at it here before any upper layer protocols do. 21062143Sarchie * 21162143Sarchie * NOTE: this function will get called at splimp() 21262143Sarchie */ 21362143Sarchiestatic void 214106933Ssamng_ether_input(struct ifnet *ifp, struct mbuf **mp) 21562143Sarchie{ 21662143Sarchie const node_p node = IFP2NG(ifp); 21770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 21862143Sarchie 21962143Sarchie /* If "lower" hook not connected, let packet continue */ 22062143Sarchie if (priv->lower == NULL || priv->lowerOrphan) 22162143Sarchie return; 222106933Ssam ng_ether_input2(node, mp); 22362143Sarchie} 22462143Sarchie 22562143Sarchie/* 22662143Sarchie * Handle a packet that has come in on an interface, and which 22762143Sarchie * does not match any of our known protocols (an ``orphan''). 22862143Sarchie * 22962143Sarchie * NOTE: this function will get called at splimp() 23062143Sarchie */ 23162143Sarchiestatic void 232106933Ssamng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 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 } 242106933Ssam ng_ether_input2(node, &m); 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 255106933Ssamng_ether_input2(node_p node, struct mbuf **mp) 25662143Sarchie{ 25770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 25862143Sarchie int error; 25962143Sarchie 26062143Sarchie /* Send out lower/orphan hook */ 26169922Sjulian NG_SEND_DATA_ONLY(error, priv->lower, *mp); 26262143Sarchie *mp = NULL; 26362143Sarchie} 26462143Sarchie 26562143Sarchie/* 26662143Sarchie * Handle a packet that is going out on an interface. 26762143Sarchie * The Ethernet header is already attached to the mbuf. 26862143Sarchie */ 26962143Sarchiestatic int 27062143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 27162143Sarchie{ 27262143Sarchie const node_p node = IFP2NG(ifp); 27370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 27462143Sarchie int error = 0; 27562143Sarchie 27662143Sarchie /* If "upper" hook not connected, let packet continue */ 27762143Sarchie if (priv->upper == NULL) 27862143Sarchie return (0); 27962143Sarchie 28062143Sarchie /* Send it out "upper" hook */ 28170700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 28262143Sarchie return (error); 28362143Sarchie} 28462143Sarchie 28562143Sarchie/* 28662143Sarchie * A new Ethernet interface has been attached. 28762143Sarchie * Create a new node for it, etc. 28862143Sarchie */ 28962143Sarchiestatic void 29062143Sarchieng_ether_attach(struct ifnet *ifp) 29162143Sarchie{ 29262143Sarchie char name[IFNAMSIZ + 1]; 29362143Sarchie priv_p priv; 29462143Sarchie node_p node; 29562143Sarchie 29662143Sarchie /* Create node */ 29787599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 29862143Sarchie snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 29962143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 30062143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 30187599Sobrien __func__, "create node", name); 30262143Sarchie return; 30362143Sarchie } 30462143Sarchie 30562143Sarchie /* Allocate private data */ 30668876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 30762143Sarchie if (priv == NULL) { 30862143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 30987599Sobrien __func__, "allocate memory", name); 31070784Sjulian NG_NODE_UNREF(node); 31162143Sarchie return; 31262143Sarchie } 31370784Sjulian NG_NODE_SET_PRIVATE(node, priv); 31462143Sarchie priv->ifp = ifp; 31562143Sarchie IFP2NG(ifp) = node; 31664358Sarchie priv->autoSrcAddr = 1; 31790249Sarchie priv->hwassist = ifp->if_hwassist; 31862143Sarchie 31962143Sarchie /* Try to give the node the same name as the interface */ 32062143Sarchie if (ng_name_node(node, name) != 0) { 32162143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 32287599Sobrien __func__, name); 32362143Sarchie } 32462143Sarchie} 32562143Sarchie 32662143Sarchie/* 32762143Sarchie * An Ethernet interface is being detached. 32871849Sjulian * REALLY Destroy its node. 32962143Sarchie */ 33062143Sarchiestatic void 33162143Sarchieng_ether_detach(struct ifnet *ifp) 33262143Sarchie{ 33362143Sarchie const node_p node = IFP2NG(ifp); 33471849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 33562143Sarchie 33662143Sarchie if (node == NULL) /* no node (why not?), ignore */ 33762143Sarchie return; 33871849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 33971849Sjulian /* 34071849Sjulian * We can't assume the ifnet is still around when we run shutdown 34171849Sjulian * So zap it now. XXX We HOPE that anything running at this time 34271849Sjulian * handles it (as it should in the non netgraph case). 34371849Sjulian */ 34471849Sjulian IFP2NG(ifp) = NULL; 34571849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 34671849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 34762143Sarchie} 34862143Sarchie 34962143Sarchie/****************************************************************** 35062143Sarchie NETGRAPH NODE METHODS 35162143Sarchie******************************************************************/ 35262143Sarchie 35362143Sarchie/* 35462143Sarchie * It is not possible or allowable to create a node of this type. 35562143Sarchie * Nodes get created when the interface is attached (or, when 35662143Sarchie * this node type's KLD is loaded). 35762143Sarchie */ 35862143Sarchiestatic int 35970700Sjulianng_ether_constructor(node_p node) 36062143Sarchie{ 36162143Sarchie return (EINVAL); 36262143Sarchie} 36362143Sarchie 36462143Sarchie/* 36562143Sarchie * Check for attaching a new hook. 36662143Sarchie */ 36762143Sarchiestatic int 36862143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 36962143Sarchie{ 37070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 37162143Sarchie u_char orphan = priv->lowerOrphan; 37262143Sarchie hook_p *hookptr; 37362143Sarchie 37462143Sarchie /* Divert hook is an alias for lower */ 37562143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 37662143Sarchie name = NG_ETHER_HOOK_LOWER; 37762143Sarchie 37862143Sarchie /* Which hook? */ 37962143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 38062143Sarchie hookptr = &priv->upper; 38162143Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 38262143Sarchie hookptr = &priv->lower; 38362143Sarchie orphan = 0; 38462143Sarchie } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 38562143Sarchie hookptr = &priv->lower; 38662143Sarchie orphan = 1; 38762143Sarchie } else 38862143Sarchie return (EINVAL); 38962143Sarchie 39062143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 39162143Sarchie if (*hookptr != NULL) 39262143Sarchie return (EISCONN); 39362143Sarchie 39490249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 39590249Sarchie if (hookptr == &priv->upper) 39690249Sarchie priv->ifp->if_hwassist = 0; 39790249Sarchie 39862143Sarchie /* OK */ 39962143Sarchie *hookptr = hook; 40062143Sarchie priv->lowerOrphan = orphan; 40162143Sarchie return (0); 40262143Sarchie} 40362143Sarchie 40462143Sarchie/* 40569922Sjulian * Hooks are attached, adjust to force queueing. 40669922Sjulian * We don't really care which hook it is. 40769922Sjulian * they should all be queuing for outgoing data. 40869922Sjulian */ 40969922Sjulianstatic int 41069922Sjulianng_ether_connect(hook_p hook) 41169922Sjulian{ 41270784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 41369922Sjulian return (0); 41469922Sjulian} 41569922Sjulian 41669922Sjulian/* 41762143Sarchie * Receive an incoming control message. 41862143Sarchie */ 41962143Sarchiestatic int 42070700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 42162143Sarchie{ 42270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 42362143Sarchie struct ng_mesg *resp = NULL; 42462143Sarchie int error = 0; 42570700Sjulian struct ng_mesg *msg; 42662143Sarchie 42770700Sjulian NGI_GET_MSG(item, msg); 42862143Sarchie switch (msg->header.typecookie) { 42962143Sarchie case NGM_ETHER_COOKIE: 43062143Sarchie switch (msg->header.cmd) { 43162143Sarchie case NGM_ETHER_GET_IFNAME: 43262143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 43362143Sarchie if (resp == NULL) { 43462143Sarchie error = ENOMEM; 43562143Sarchie break; 43662143Sarchie } 43762143Sarchie snprintf(resp->data, IFNAMSIZ + 1, 43862143Sarchie "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 43962143Sarchie break; 44062143Sarchie case NGM_ETHER_GET_IFINDEX: 44162143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 44262143Sarchie if (resp == NULL) { 44362143Sarchie error = ENOMEM; 44462143Sarchie break; 44562143Sarchie } 44662143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 44762143Sarchie break; 44864358Sarchie case NGM_ETHER_GET_ENADDR: 44964358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 45064358Sarchie if (resp == NULL) { 45164358Sarchie error = ENOMEM; 45264358Sarchie break; 45364358Sarchie } 45464358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 45564358Sarchie resp->data, ETHER_ADDR_LEN); 45664358Sarchie break; 45764653Sarchie case NGM_ETHER_SET_ENADDR: 45864653Sarchie { 45964653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 46064653Sarchie error = EINVAL; 46164653Sarchie break; 46264653Sarchie } 46364653Sarchie error = if_setlladdr(priv->ifp, 46464653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 46564653Sarchie break; 46664653Sarchie } 46764653Sarchie case NGM_ETHER_GET_PROMISC: 46864653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 46964653Sarchie if (resp == NULL) { 47064653Sarchie error = ENOMEM; 47164653Sarchie break; 47264653Sarchie } 47364653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 47464653Sarchie break; 47564358Sarchie case NGM_ETHER_SET_PROMISC: 47664358Sarchie { 47764358Sarchie u_char want; 47864358Sarchie 47964358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 48064358Sarchie error = EINVAL; 48164358Sarchie break; 48264358Sarchie } 48364358Sarchie want = !!*((u_int32_t *)msg->data); 48464358Sarchie if (want ^ priv->promisc) { 48564358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 48664358Sarchie break; 48764358Sarchie priv->promisc = want; 48864358Sarchie } 48964358Sarchie break; 49064358Sarchie } 49164653Sarchie case NGM_ETHER_GET_AUTOSRC: 49264653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 49364653Sarchie if (resp == NULL) { 49464653Sarchie error = ENOMEM; 49564653Sarchie break; 49664653Sarchie } 49764653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 49864653Sarchie break; 49964358Sarchie case NGM_ETHER_SET_AUTOSRC: 50064358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 50164358Sarchie error = EINVAL; 50264358Sarchie break; 50364358Sarchie } 50464358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 50564358Sarchie break; 50662143Sarchie default: 50762143Sarchie error = EINVAL; 50862143Sarchie break; 50962143Sarchie } 51062143Sarchie break; 51162143Sarchie default: 51262143Sarchie error = EINVAL; 51362143Sarchie break; 51462143Sarchie } 51570700Sjulian NG_RESPOND_MSG(error, node, item, resp); 51670700Sjulian NG_FREE_MSG(msg); 51762143Sarchie return (error); 51862143Sarchie} 51962143Sarchie 52062143Sarchie/* 52162143Sarchie * Receive data on a hook. 52262143Sarchie */ 52362143Sarchiestatic int 52470700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 52562143Sarchie{ 52670784Sjulian const node_p node = NG_HOOK_NODE(hook); 52770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 52870700Sjulian struct mbuf *m; 52970700Sjulian meta_p meta; 53062143Sarchie 53170700Sjulian NGI_GET_M(item, m); 53270700Sjulian NGI_GET_META(item, meta); 53370700Sjulian NG_FREE_ITEM(item); 53462143Sarchie if (hook == priv->lower) 53562143Sarchie return ng_ether_rcv_lower(node, m, meta); 53662143Sarchie if (hook == priv->upper) 53762143Sarchie return ng_ether_rcv_upper(node, m, meta); 53887599Sobrien panic("%s: weird hook", __func__); 53983366Sjulian#ifdef RESTARTABLE_PANICS /* so we don;t get an error msg in LINT */ 54083366Sjulian return NULL; 54183366Sjulian#endif 54262143Sarchie} 54362143Sarchie 54462143Sarchie/* 54562143Sarchie * Handle an mbuf received on the "lower" hook. 54662143Sarchie */ 54762143Sarchiestatic int 54862143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 54962143Sarchie{ 55070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 55196265Sarchie struct ifnet *const ifp = priv->ifp; 55262143Sarchie 55397896Sarchie /* Discard meta info */ 55497896Sarchie NG_FREE_META(meta); 55597896Sarchie 55696265Sarchie /* Check whether interface is ready for packets */ 55796265Sarchie if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 55896265Sarchie NG_FREE_M(m); 55996265Sarchie return (ENETDOWN); 56096265Sarchie } 56196265Sarchie 56262143Sarchie /* Make sure header is fully pulled up */ 56362143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 56470700Sjulian NG_FREE_M(m); 56562143Sarchie return (EINVAL); 56662143Sarchie } 56762143Sarchie if (m->m_len < sizeof(struct ether_header) 56897896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 56962143Sarchie return (ENOBUFS); 57062143Sarchie 57164358Sarchie /* Drop in the MAC address if desired */ 57264358Sarchie if (priv->autoSrcAddr) { 57397896Sarchie 57497896Sarchie /* Make the mbuf writable if it's not already */ 57597896Sarchie if (!M_WRITABLE(m) 57697896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 57797896Sarchie return (ENOBUFS); 57897896Sarchie 57997896Sarchie /* Overwrite source MAC address */ 58096265Sarchie bcopy((IFP2AC(ifp))->ac_enaddr, 58164358Sarchie mtod(m, struct ether_header *)->ether_shost, 58264358Sarchie ETHER_ADDR_LEN); 58364358Sarchie } 58462678Sjulian 58562143Sarchie /* Send it on its way */ 58696265Sarchie return ether_output_frame(ifp, m); 58762143Sarchie} 58862143Sarchie 58962143Sarchie/* 59062143Sarchie * Handle an mbuf received on the "upper" hook. 59162143Sarchie */ 59262143Sarchiestatic int 59362143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 59462143Sarchie{ 59570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 59662143Sarchie 59797896Sarchie /* Discard meta info */ 59897896Sarchie NG_FREE_META(meta); 59997896Sarchie 60066061Sjulian m->m_pkthdr.rcvif = priv->ifp; 60162143Sarchie 60262143Sarchie /* Route packet back in */ 603106933Ssam ether_demux(priv->ifp, m); 60462143Sarchie return (0); 60562143Sarchie} 60662143Sarchie 60762143Sarchie/* 60871849Sjulian * Shutdown node. This resets the node but does not remove it 60971849Sjulian * unless the REALLY_DIE flag is set. 61062143Sarchie */ 61162143Sarchiestatic int 61270700Sjulianng_ether_shutdown(node_p node) 61362143Sarchie{ 61470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 61564358Sarchie 61664358Sarchie if (priv->promisc) { /* disable promiscuous mode */ 61764358Sarchie (void)ifpromisc(priv->ifp, 0); 61864358Sarchie priv->promisc = 0; 61964358Sarchie } 62071849Sjulian if (node->nd_flags & NG_REALLY_DIE) { 62171849Sjulian /* 62271849Sjulian * WE came here because the ethernet card is being unloaded, 62371849Sjulian * so stop being persistant. 62471849Sjulian * Actually undo all the things we did on creation. 62571849Sjulian * Assume the ifp has already been freed. 62671849Sjulian */ 62771849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 62871849Sjulian FREE(priv, M_NETGRAPH); 62971849Sjulian NG_NODE_UNREF(node); /* free node itself */ 63071849Sjulian return (0); 63170700Sjulian } 63264358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 63371849Sjulian node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */ 63462143Sarchie return (0); 63562143Sarchie} 63662143Sarchie 63762143Sarchie/* 63862143Sarchie * Hook disconnection. 63962143Sarchie */ 64062143Sarchiestatic int 64162143Sarchieng_ether_disconnect(hook_p hook) 64262143Sarchie{ 64370784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 64462143Sarchie 64590249Sarchie if (hook == priv->upper) { 64662143Sarchie priv->upper = NULL; 64790249Sarchie priv->ifp->if_hwassist = priv->hwassist; /* restore h/w csum */ 64890249Sarchie } else if (hook == priv->lower) { 64962143Sarchie priv->lower = NULL; 65062143Sarchie priv->lowerOrphan = 0; 65162143Sarchie } else 65287599Sobrien panic("%s: weird hook", __func__); 65370784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 65470784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 65570784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 65662143Sarchie return (0); 65762143Sarchie} 65862143Sarchie 65964653Sarchiestatic int 66064653Sarchieng_enaddr_parse(const struct ng_parse_type *type, 66164653Sarchie const char *s, int *const off, const u_char *const start, 66264653Sarchie u_char *const buf, int *const buflen) 66364653Sarchie{ 66464653Sarchie char *eptr; 66564653Sarchie u_long val; 66664653Sarchie int i; 66764653Sarchie 66864653Sarchie if (*buflen < ETHER_ADDR_LEN) 66964653Sarchie return (ERANGE); 67064653Sarchie for (i = 0; i < ETHER_ADDR_LEN; i++) { 67164653Sarchie val = strtoul(s + *off, &eptr, 16); 67264653Sarchie if (val > 0xff || eptr == s + *off) 67364653Sarchie return (EINVAL); 67464653Sarchie buf[i] = (u_char)val; 67564653Sarchie *off = (eptr - s); 67664653Sarchie if (i < ETHER_ADDR_LEN - 1) { 67764653Sarchie if (*eptr != ':') 67864653Sarchie return (EINVAL); 67964653Sarchie (*off)++; 68064653Sarchie } 68164653Sarchie } 68264653Sarchie *buflen = ETHER_ADDR_LEN; 68364653Sarchie return (0); 68464653Sarchie} 68564653Sarchie 68664653Sarchiestatic int 68764653Sarchieng_enaddr_unparse(const struct ng_parse_type *type, 68864653Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 68964653Sarchie{ 69064653Sarchie int len; 69164653Sarchie 69264653Sarchie len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 69365305Sarchie data[*off], data[*off + 1], data[*off + 2], 69465305Sarchie data[*off + 3], data[*off + 4], data[*off + 5]); 69564653Sarchie if (len >= cbuflen) 69664653Sarchie return (ERANGE); 69764653Sarchie *off += ETHER_ADDR_LEN; 69864653Sarchie return (0); 69964653Sarchie} 70064653Sarchie 70162143Sarchie/****************************************************************** 70262143Sarchie INITIALIZATION 70362143Sarchie******************************************************************/ 70462143Sarchie 70562143Sarchie/* 70662143Sarchie * Handle loading and unloading for this node type. 70762143Sarchie */ 70862143Sarchiestatic int 70962143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 71062143Sarchie{ 71162143Sarchie struct ifnet *ifp; 71262143Sarchie int error = 0; 71362143Sarchie int s; 71462143Sarchie 71562143Sarchie s = splnet(); 71662143Sarchie switch (event) { 71762143Sarchie case MOD_LOAD: 71862143Sarchie 71962143Sarchie /* Register function hooks */ 72062143Sarchie if (ng_ether_attach_p != NULL) { 72162143Sarchie error = EEXIST; 72262143Sarchie break; 72362143Sarchie } 72462143Sarchie ng_ether_attach_p = ng_ether_attach; 72562143Sarchie ng_ether_detach_p = ng_ether_detach; 72662143Sarchie ng_ether_output_p = ng_ether_output; 72762143Sarchie ng_ether_input_p = ng_ether_input; 72862143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 72962143Sarchie 73062143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 73162143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 73282586Sarchie if (ifp->if_type == IFT_ETHER 73382586Sarchie || ifp->if_type == IFT_L2VLAN) 73462143Sarchie ng_ether_attach(ifp); 73562143Sarchie } 73662143Sarchie break; 73762143Sarchie 73862143Sarchie case MOD_UNLOAD: 73962143Sarchie 74062143Sarchie /* 74162143Sarchie * Note that the base code won't try to unload us until 74262143Sarchie * all nodes have been removed, and that can't happen 74362143Sarchie * until all Ethernet interfaces are removed. In any 74462143Sarchie * case, we know there are no nodes left if the action 74562143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 74662143Sarchie */ 74762143Sarchie 74862143Sarchie /* Unregister function hooks */ 74962143Sarchie ng_ether_attach_p = NULL; 75062143Sarchie ng_ether_detach_p = NULL; 75162143Sarchie ng_ether_output_p = NULL; 75262143Sarchie ng_ether_input_p = NULL; 75362143Sarchie ng_ether_input_orphan_p = NULL; 75462143Sarchie break; 75562143Sarchie 75662143Sarchie default: 75762143Sarchie error = EOPNOTSUPP; 75862143Sarchie break; 75962143Sarchie } 76062143Sarchie splx(s); 76162143Sarchie return (error); 76262143Sarchie} 76362143Sarchie 764