ng_ether.c revision 129281
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 129281 2004-05-16 19:31:35Z 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 6762143Sarchie#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph) 6862143Sarchie 69126035Spjd/* Per-node private data */ 70126035Spjdstruct private { 71126035Spjd struct ifnet *ifp; /* associated interface */ 72126035Spjd hook_p upper; /* upper hook connection */ 73129281Sarchie hook_p lower; /* lower hook connection */ 74129281Sarchie hook_p orphan; /* orphan hook connection */ 75126035Spjd u_char autoSrcAddr; /* always overwrite source address */ 76126035Spjd u_char promisc; /* promiscuous mode enabled */ 77126035Spjd u_long hwassist; /* hardware checksum capabilities */ 78126035Spjd u_int flags; /* flags e.g. really die */ 79126035Spjd}; 80126035Spjdtypedef struct private *priv_p; 8162143Sarchie 82106933Ssam/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 83106933Ssamextern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 84106933Ssamextern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 85106933Ssamextern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 86106933Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 87106933Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 88106933Ssam 8962143Sarchie/* Functional hooks called from if_ethersubr.c */ 90106933Ssamstatic void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 91106933Ssamstatic void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 9262143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 9362143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 9462143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 9562143Sarchie 9662143Sarchie/* Other functions */ 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 11062143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 11162143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 11262143Sarchie { 11362143Sarchie NGM_ETHER_COOKIE, 11462143Sarchie NGM_ETHER_GET_IFNAME, 11562143Sarchie "getifname", 11662143Sarchie NULL, 11762143Sarchie &ng_parse_string_type 11862143Sarchie }, 11962143Sarchie { 12062143Sarchie NGM_ETHER_COOKIE, 12162143Sarchie NGM_ETHER_GET_IFINDEX, 12262143Sarchie "getifindex", 12362143Sarchie NULL, 12462143Sarchie &ng_parse_int32_type 12562143Sarchie }, 12664358Sarchie { 12764358Sarchie NGM_ETHER_COOKIE, 12864358Sarchie NGM_ETHER_GET_ENADDR, 12964358Sarchie "getenaddr", 13064358Sarchie NULL, 131123600Sru &ng_parse_enaddr_type 13264358Sarchie }, 13364358Sarchie { 13464358Sarchie NGM_ETHER_COOKIE, 13564653Sarchie NGM_ETHER_SET_ENADDR, 13664653Sarchie "setenaddr", 137123600Sru &ng_parse_enaddr_type, 13864653Sarchie NULL 13964653Sarchie }, 14064653Sarchie { 14164653Sarchie NGM_ETHER_COOKIE, 14264653Sarchie NGM_ETHER_GET_PROMISC, 14364653Sarchie "getpromisc", 14464653Sarchie NULL, 14564653Sarchie &ng_parse_int32_type 14664653Sarchie }, 14764653Sarchie { 14864653Sarchie NGM_ETHER_COOKIE, 14964358Sarchie NGM_ETHER_SET_PROMISC, 15064358Sarchie "setpromisc", 15164358Sarchie &ng_parse_int32_type, 15264358Sarchie NULL 15364358Sarchie }, 15464358Sarchie { 15564358Sarchie NGM_ETHER_COOKIE, 15664653Sarchie NGM_ETHER_GET_AUTOSRC, 15764653Sarchie "getautosrc", 15864653Sarchie NULL, 15964653Sarchie &ng_parse_int32_type 16064653Sarchie }, 16164653Sarchie { 16264653Sarchie NGM_ETHER_COOKIE, 16364358Sarchie NGM_ETHER_SET_AUTOSRC, 16464358Sarchie "setautosrc", 16564358Sarchie &ng_parse_int32_type, 16664358Sarchie NULL 16764358Sarchie }, 16862143Sarchie { 0 } 16962143Sarchie}; 17062143Sarchie 17162143Sarchiestatic struct ng_type ng_ether_typestruct = { 17270159Sjulian NG_ABI_VERSION, 17362143Sarchie NG_ETHER_NODE_TYPE, 17462143Sarchie ng_ether_mod_event, 17562143Sarchie ng_ether_constructor, 17662143Sarchie ng_ether_rcvmsg, 17770700Sjulian ng_ether_shutdown, 17862143Sarchie ng_ether_newhook, 17962143Sarchie NULL, 18069922Sjulian ng_ether_connect, 18162143Sarchie ng_ether_rcvdata, 18262143Sarchie ng_ether_disconnect, 18362143Sarchie ng_ether_cmdlist, 18462143Sarchie}; 18571047SjulianMODULE_VERSION(ng_ether, 1); 18662143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 18762143Sarchie 18862143Sarchie/****************************************************************** 18962143Sarchie ETHERNET FUNCTION HOOKS 19062143Sarchie******************************************************************/ 19162143Sarchie 19262143Sarchie/* 19362143Sarchie * Handle a packet that has come in on an interface. We get to 19462143Sarchie * look at it here before any upper layer protocols do. 19562143Sarchie * 19662143Sarchie * NOTE: this function will get called at splimp() 19762143Sarchie */ 19862143Sarchiestatic void 199106933Ssamng_ether_input(struct ifnet *ifp, struct mbuf **mp) 20062143Sarchie{ 20162143Sarchie const node_p node = IFP2NG(ifp); 20270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 203129281Sarchie int error; 20462143Sarchie 20562143Sarchie /* If "lower" hook not connected, let packet continue */ 206129281Sarchie if (priv->lower == NULL) 20762143Sarchie return; 208129281Sarchie NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */ 20962143Sarchie} 21062143Sarchie 21162143Sarchie/* 21262143Sarchie * Handle a packet that has come in on an interface, and which 21362143Sarchie * does not match any of our known protocols (an ``orphan''). 21462143Sarchie * 21562143Sarchie * NOTE: this function will get called at splimp() 21662143Sarchie */ 21762143Sarchiestatic void 218106933Ssamng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 21962143Sarchie{ 22062143Sarchie const node_p node = IFP2NG(ifp); 22170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 222129281Sarchie int error; 22362143Sarchie 224129281Sarchie /* If "orphan" hook not connected, discard packet */ 225129281Sarchie if (priv->orphan == NULL) { 22662143Sarchie m_freem(m); 22762143Sarchie return; 22862143Sarchie } 229129281Sarchie NG_SEND_DATA_ONLY(error, priv->orphan, m); 23062143Sarchie} 23162143Sarchie 23262143Sarchie/* 23362143Sarchie * Handle a packet that is going out on an interface. 23462143Sarchie * The Ethernet header is already attached to the mbuf. 23562143Sarchie */ 23662143Sarchiestatic int 23762143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 23862143Sarchie{ 23962143Sarchie const node_p node = IFP2NG(ifp); 24070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 24162143Sarchie int error = 0; 24262143Sarchie 24362143Sarchie /* If "upper" hook not connected, let packet continue */ 24462143Sarchie if (priv->upper == NULL) 24562143Sarchie return (0); 24662143Sarchie 24762143Sarchie /* Send it out "upper" hook */ 24870700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 24962143Sarchie return (error); 25062143Sarchie} 25162143Sarchie 25262143Sarchie/* 25362143Sarchie * A new Ethernet interface has been attached. 25462143Sarchie * Create a new node for it, etc. 25562143Sarchie */ 25662143Sarchiestatic void 25762143Sarchieng_ether_attach(struct ifnet *ifp) 25862143Sarchie{ 25962143Sarchie priv_p priv; 26062143Sarchie node_p node; 26162143Sarchie 26262143Sarchie /* Create node */ 26387599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 26462143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 26562143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 266121816Sbrooks __func__, "create node", ifp->if_xname); 26762143Sarchie return; 26862143Sarchie } 26962143Sarchie 27062143Sarchie /* Allocate private data */ 27168876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 27262143Sarchie if (priv == NULL) { 27362143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 274121816Sbrooks __func__, "allocate memory", ifp->if_xname); 27570784Sjulian NG_NODE_UNREF(node); 27662143Sarchie return; 27762143Sarchie } 27870784Sjulian NG_NODE_SET_PRIVATE(node, priv); 27962143Sarchie priv->ifp = ifp; 28062143Sarchie IFP2NG(ifp) = node; 28164358Sarchie priv->autoSrcAddr = 1; 28290249Sarchie priv->hwassist = ifp->if_hwassist; 28362143Sarchie 28462143Sarchie /* Try to give the node the same name as the interface */ 285121816Sbrooks if (ng_name_node(node, ifp->if_xname) != 0) { 28662143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 287121816Sbrooks __func__, ifp->if_xname); 28862143Sarchie } 28962143Sarchie} 29062143Sarchie 29162143Sarchie/* 29262143Sarchie * An Ethernet interface is being detached. 29371849Sjulian * REALLY Destroy its node. 29462143Sarchie */ 29562143Sarchiestatic void 29662143Sarchieng_ether_detach(struct ifnet *ifp) 29762143Sarchie{ 29862143Sarchie const node_p node = IFP2NG(ifp); 29971849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 30062143Sarchie 30162143Sarchie if (node == NULL) /* no node (why not?), ignore */ 30262143Sarchie return; 30371849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 30471849Sjulian /* 30571849Sjulian * We can't assume the ifnet is still around when we run shutdown 30671849Sjulian * So zap it now. XXX We HOPE that anything running at this time 30771849Sjulian * handles it (as it should in the non netgraph case). 30871849Sjulian */ 30971849Sjulian IFP2NG(ifp) = NULL; 31071849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 31171849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 31262143Sarchie} 31362143Sarchie 31462143Sarchie/****************************************************************** 31562143Sarchie NETGRAPH NODE METHODS 31662143Sarchie******************************************************************/ 31762143Sarchie 31862143Sarchie/* 31962143Sarchie * It is not possible or allowable to create a node of this type. 32062143Sarchie * Nodes get created when the interface is attached (or, when 32162143Sarchie * this node type's KLD is loaded). 32262143Sarchie */ 32362143Sarchiestatic int 32470700Sjulianng_ether_constructor(node_p node) 32562143Sarchie{ 32662143Sarchie return (EINVAL); 32762143Sarchie} 32862143Sarchie 32962143Sarchie/* 33062143Sarchie * Check for attaching a new hook. 33162143Sarchie */ 33262143Sarchiestatic int 33362143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 33462143Sarchie{ 33570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 33662143Sarchie hook_p *hookptr; 33762143Sarchie 33862143Sarchie /* Divert hook is an alias for lower */ 33962143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 34062143Sarchie name = NG_ETHER_HOOK_LOWER; 34162143Sarchie 34262143Sarchie /* Which hook? */ 34362143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 34462143Sarchie hookptr = &priv->upper; 345129281Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) 34662143Sarchie hookptr = &priv->lower; 347129281Sarchie else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) 348129281Sarchie hookptr = &priv->orphan; 349129281Sarchie else 35062143Sarchie return (EINVAL); 35162143Sarchie 35262143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 35362143Sarchie if (*hookptr != NULL) 35462143Sarchie return (EISCONN); 35562143Sarchie 35690249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 35790249Sarchie if (hookptr == &priv->upper) 35890249Sarchie priv->ifp->if_hwassist = 0; 35990249Sarchie 36062143Sarchie /* OK */ 36162143Sarchie *hookptr = hook; 36262143Sarchie return (0); 36362143Sarchie} 36462143Sarchie 36562143Sarchie/* 36669922Sjulian * Hooks are attached, adjust to force queueing. 36769922Sjulian * We don't really care which hook it is. 36869922Sjulian * they should all be queuing for outgoing data. 36969922Sjulian */ 37069922Sjulianstatic int 37169922Sjulianng_ether_connect(hook_p hook) 37269922Sjulian{ 37370784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 37469922Sjulian return (0); 37569922Sjulian} 37669922Sjulian 37769922Sjulian/* 37862143Sarchie * Receive an incoming control message. 37962143Sarchie */ 38062143Sarchiestatic int 38170700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 38262143Sarchie{ 38370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 38462143Sarchie struct ng_mesg *resp = NULL; 38562143Sarchie int error = 0; 38670700Sjulian struct ng_mesg *msg; 38762143Sarchie 38870700Sjulian NGI_GET_MSG(item, msg); 38962143Sarchie switch (msg->header.typecookie) { 39062143Sarchie case NGM_ETHER_COOKIE: 39162143Sarchie switch (msg->header.cmd) { 39262143Sarchie case NGM_ETHER_GET_IFNAME: 39362143Sarchie NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 39462143Sarchie if (resp == NULL) { 39562143Sarchie error = ENOMEM; 39662143Sarchie break; 39762143Sarchie } 398121816Sbrooks strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1); 39962143Sarchie break; 40062143Sarchie case NGM_ETHER_GET_IFINDEX: 40162143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 40262143Sarchie if (resp == NULL) { 40362143Sarchie error = ENOMEM; 40462143Sarchie break; 40562143Sarchie } 40662143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 40762143Sarchie break; 40864358Sarchie case NGM_ETHER_GET_ENADDR: 40964358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 41064358Sarchie if (resp == NULL) { 41164358Sarchie error = ENOMEM; 41264358Sarchie break; 41364358Sarchie } 41464358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 41564358Sarchie resp->data, ETHER_ADDR_LEN); 41664358Sarchie break; 41764653Sarchie case NGM_ETHER_SET_ENADDR: 41864653Sarchie { 41964653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 42064653Sarchie error = EINVAL; 42164653Sarchie break; 42264653Sarchie } 42364653Sarchie error = if_setlladdr(priv->ifp, 42464653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 42564653Sarchie break; 42664653Sarchie } 42764653Sarchie case NGM_ETHER_GET_PROMISC: 42864653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 42964653Sarchie if (resp == NULL) { 43064653Sarchie error = ENOMEM; 43164653Sarchie break; 43264653Sarchie } 43364653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 43464653Sarchie break; 43564358Sarchie case NGM_ETHER_SET_PROMISC: 43664358Sarchie { 43764358Sarchie u_char want; 43864358Sarchie 43964358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 44064358Sarchie error = EINVAL; 44164358Sarchie break; 44264358Sarchie } 44364358Sarchie want = !!*((u_int32_t *)msg->data); 44464358Sarchie if (want ^ priv->promisc) { 44564358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 44664358Sarchie break; 44764358Sarchie priv->promisc = want; 44864358Sarchie } 44964358Sarchie break; 45064358Sarchie } 45164653Sarchie case NGM_ETHER_GET_AUTOSRC: 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->autoSrcAddr; 45864653Sarchie break; 45964358Sarchie case NGM_ETHER_SET_AUTOSRC: 46064358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 46164358Sarchie error = EINVAL; 46264358Sarchie break; 46364358Sarchie } 46464358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 46564358Sarchie break; 46662143Sarchie default: 46762143Sarchie error = EINVAL; 46862143Sarchie break; 46962143Sarchie } 47062143Sarchie break; 47162143Sarchie default: 47262143Sarchie error = EINVAL; 47362143Sarchie break; 47462143Sarchie } 47570700Sjulian NG_RESPOND_MSG(error, node, item, resp); 47670700Sjulian NG_FREE_MSG(msg); 47762143Sarchie return (error); 47862143Sarchie} 47962143Sarchie 48062143Sarchie/* 48162143Sarchie * Receive data on a hook. 48262143Sarchie */ 48362143Sarchiestatic int 48470700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 48562143Sarchie{ 48670784Sjulian const node_p node = NG_HOOK_NODE(hook); 48770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 48870700Sjulian struct mbuf *m; 48970700Sjulian meta_p meta; 49062143Sarchie 49170700Sjulian NGI_GET_M(item, m); 49270700Sjulian NGI_GET_META(item, meta); 49370700Sjulian NG_FREE_ITEM(item); 494129281Sarchie if (hook == priv->lower || hook == priv->orphan) 49562143Sarchie return ng_ether_rcv_lower(node, m, meta); 49662143Sarchie if (hook == priv->upper) 49762143Sarchie return ng_ether_rcv_upper(node, m, meta); 49887599Sobrien panic("%s: weird hook", __func__); 499129281Sarchie#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */ 50083366Sjulian return NULL; 50183366Sjulian#endif 50262143Sarchie} 50362143Sarchie 50462143Sarchie/* 505129281Sarchie * Handle an mbuf received on the "lower" or "orphan" hook. 50662143Sarchie */ 50762143Sarchiestatic int 50862143Sarchieng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 50962143Sarchie{ 51070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 51196265Sarchie struct ifnet *const ifp = priv->ifp; 51262143Sarchie 51397896Sarchie /* Discard meta info */ 51497896Sarchie NG_FREE_META(meta); 51597896Sarchie 51696265Sarchie /* Check whether interface is ready for packets */ 51796265Sarchie if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 51896265Sarchie NG_FREE_M(m); 51996265Sarchie return (ENETDOWN); 52096265Sarchie } 52196265Sarchie 52262143Sarchie /* Make sure header is fully pulled up */ 52362143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 52470700Sjulian NG_FREE_M(m); 52562143Sarchie return (EINVAL); 52662143Sarchie } 52762143Sarchie if (m->m_len < sizeof(struct ether_header) 52897896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 52962143Sarchie return (ENOBUFS); 53062143Sarchie 53164358Sarchie /* Drop in the MAC address if desired */ 53264358Sarchie if (priv->autoSrcAddr) { 53397896Sarchie 53497896Sarchie /* Make the mbuf writable if it's not already */ 53597896Sarchie if (!M_WRITABLE(m) 53697896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 53797896Sarchie return (ENOBUFS); 53897896Sarchie 53997896Sarchie /* Overwrite source MAC address */ 54096265Sarchie bcopy((IFP2AC(ifp))->ac_enaddr, 54164358Sarchie mtod(m, struct ether_header *)->ether_shost, 54264358Sarchie ETHER_ADDR_LEN); 54364358Sarchie } 54462678Sjulian 54562143Sarchie /* Send it on its way */ 54696265Sarchie return ether_output_frame(ifp, m); 54762143Sarchie} 54862143Sarchie 54962143Sarchie/* 55062143Sarchie * Handle an mbuf received on the "upper" hook. 55162143Sarchie */ 55262143Sarchiestatic int 55362143Sarchieng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 55462143Sarchie{ 55570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 55662143Sarchie 55797896Sarchie /* Discard meta info */ 55897896Sarchie NG_FREE_META(meta); 55997896Sarchie 56066061Sjulian m->m_pkthdr.rcvif = priv->ifp; 56162143Sarchie 56262143Sarchie /* Route packet back in */ 563106933Ssam ether_demux(priv->ifp, m); 56462143Sarchie return (0); 56562143Sarchie} 56662143Sarchie 56762143Sarchie/* 56871849Sjulian * Shutdown node. This resets the node but does not remove it 56971849Sjulian * unless the REALLY_DIE flag is set. 57062143Sarchie */ 57162143Sarchiestatic int 57270700Sjulianng_ether_shutdown(node_p node) 57362143Sarchie{ 57470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 57564358Sarchie 57671849Sjulian if (node->nd_flags & NG_REALLY_DIE) { 57771849Sjulian /* 57871849Sjulian * WE came here because the ethernet card is being unloaded, 57971849Sjulian * so stop being persistant. 58071849Sjulian * Actually undo all the things we did on creation. 58171849Sjulian * Assume the ifp has already been freed. 58271849Sjulian */ 58371849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 58471849Sjulian FREE(priv, M_NETGRAPH); 58571849Sjulian NG_NODE_UNREF(node); /* free node itself */ 58671849Sjulian return (0); 58770700Sjulian } 588124269Sgreen if (priv->promisc) { /* disable promiscuous mode */ 589124269Sgreen (void)ifpromisc(priv->ifp, 0); 590124269Sgreen priv->promisc = 0; 591124269Sgreen } 59264358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 59371849Sjulian node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */ 59462143Sarchie return (0); 59562143Sarchie} 59662143Sarchie 59762143Sarchie/* 59862143Sarchie * Hook disconnection. 59962143Sarchie */ 60062143Sarchiestatic int 60162143Sarchieng_ether_disconnect(hook_p hook) 60262143Sarchie{ 60370784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 60462143Sarchie 60590249Sarchie if (hook == priv->upper) { 60662143Sarchie priv->upper = NULL; 607124270Sgreen if (priv->ifp != NULL) /* restore h/w csum */ 608124270Sgreen priv->ifp->if_hwassist = priv->hwassist; 609129281Sarchie } else if (hook == priv->lower) 61062143Sarchie priv->lower = NULL; 611129281Sarchie else if (hook == priv->orphan) 612129281Sarchie priv->orphan = NULL; 613129281Sarchie else 61487599Sobrien panic("%s: weird hook", __func__); 61570784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 61670784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 61770784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 61862143Sarchie return (0); 61962143Sarchie} 62062143Sarchie 62162143Sarchie/****************************************************************** 62262143Sarchie INITIALIZATION 62362143Sarchie******************************************************************/ 62462143Sarchie 62562143Sarchie/* 62662143Sarchie * Handle loading and unloading for this node type. 62762143Sarchie */ 62862143Sarchiestatic int 62962143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 63062143Sarchie{ 63162143Sarchie struct ifnet *ifp; 63262143Sarchie int error = 0; 63362143Sarchie int s; 63462143Sarchie 63562143Sarchie s = splnet(); 63662143Sarchie switch (event) { 63762143Sarchie case MOD_LOAD: 63862143Sarchie 63962143Sarchie /* Register function hooks */ 64062143Sarchie if (ng_ether_attach_p != NULL) { 64162143Sarchie error = EEXIST; 64262143Sarchie break; 64362143Sarchie } 64462143Sarchie ng_ether_attach_p = ng_ether_attach; 64562143Sarchie ng_ether_detach_p = ng_ether_detach; 64662143Sarchie ng_ether_output_p = ng_ether_output; 64762143Sarchie ng_ether_input_p = ng_ether_input; 64862143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 64962143Sarchie 65062143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 651108172Shsu IFNET_RLOCK(); 65262143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 65382586Sarchie if (ifp->if_type == IFT_ETHER 65482586Sarchie || ifp->if_type == IFT_L2VLAN) 65562143Sarchie ng_ether_attach(ifp); 65662143Sarchie } 657108172Shsu IFNET_RUNLOCK(); 65862143Sarchie break; 65962143Sarchie 66062143Sarchie case MOD_UNLOAD: 66162143Sarchie 66262143Sarchie /* 66362143Sarchie * Note that the base code won't try to unload us until 66462143Sarchie * all nodes have been removed, and that can't happen 66562143Sarchie * until all Ethernet interfaces are removed. In any 66662143Sarchie * case, we know there are no nodes left if the action 66762143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 66862143Sarchie */ 66962143Sarchie 67062143Sarchie /* Unregister function hooks */ 67162143Sarchie ng_ether_attach_p = NULL; 67262143Sarchie ng_ether_detach_p = NULL; 67362143Sarchie ng_ether_output_p = NULL; 67462143Sarchie ng_ether_input_p = NULL; 67562143Sarchie ng_ether_input_orphan_p = NULL; 67662143Sarchie break; 67762143Sarchie 67862143Sarchie default: 67962143Sarchie error = EOPNOTSUPP; 68062143Sarchie break; 68162143Sarchie } 68262143Sarchie splx(s); 68362143Sarchie return (error); 68462143Sarchie} 68562143Sarchie 686