ng_ether.c revision 141721
162143Sarchie 262143Sarchie/* 362143Sarchie * ng_ether.c 4139823Simp */ 5139823Simp 6139823Simp/*- 762143Sarchie * Copyright (c) 1996-2000 Whistle Communications, Inc. 862143Sarchie * All rights reserved. 962143Sarchie * 1062143Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1162143Sarchie * redistribution of this software, in source or object code forms, with or 1262143Sarchie * without modifications are expressly permitted by Whistle Communications; 1362143Sarchie * provided, however, that: 1462143Sarchie * 1. Any and all reproductions of the source or object code must include the 1562143Sarchie * copyright notice above and the following disclaimer of warranties; and 1662143Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1762143Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1862143Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1962143Sarchie * such appears in the above copyright notice or in the software. 2062143Sarchie * 2162143Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2262143Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2362143Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2462143Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2562143Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2662143Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2762143Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2862143Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2962143Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 3062143Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3162143Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3262143Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3362143Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3462143Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3562143Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3662143Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3762143Sarchie * OF SUCH DAMAGE. 3862143Sarchie * 3962143Sarchie * Authors: Archie Cobbs <archie@freebsd.org> 4062143Sarchie * Julian Elischer <julian@freebsd.org> 4162143Sarchie * 4262143Sarchie * $FreeBSD: head/sys/netgraph/ng_ether.c 141721 2005-02-12 11:41:32Z glebius $ 4362143Sarchie */ 4462143Sarchie 4562143Sarchie/* 4662143Sarchie * ng_ether(4) netgraph node type 4762143Sarchie */ 4862143Sarchie 4962143Sarchie#include <sys/param.h> 5062143Sarchie#include <sys/systm.h> 5162143Sarchie#include <sys/kernel.h> 5262143Sarchie#include <sys/malloc.h> 5362143Sarchie#include <sys/mbuf.h> 5462143Sarchie#include <sys/errno.h> 5562143Sarchie#include <sys/syslog.h> 5662143Sarchie#include <sys/socket.h> 5762143Sarchie 58136428Sglebius#include <net/bridge.h> 5962143Sarchie#include <net/if.h> 60141721Sglebius#include <net/if_dl.h> 6162143Sarchie#include <net/if_types.h> 6262143Sarchie#include <net/if_arp.h> 6362143Sarchie#include <net/if_var.h> 6462143Sarchie#include <net/ethernet.h> 6562143Sarchie 6662143Sarchie#include <netgraph/ng_message.h> 6762143Sarchie#include <netgraph/netgraph.h> 6862143Sarchie#include <netgraph/ng_parse.h> 6962143Sarchie#include <netgraph/ng_ether.h> 7062143Sarchie 7162143Sarchie#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph) 72132780Skan#define IFP2NG_SET(ifp, val) (((struct arpcom *)(ifp))->ac_netgraph = (val)) 7362143Sarchie 74126035Spjd/* Per-node private data */ 75126035Spjdstruct private { 76126035Spjd struct ifnet *ifp; /* associated interface */ 77126035Spjd hook_p upper; /* upper hook connection */ 78129281Sarchie hook_p lower; /* lower hook connection */ 79129281Sarchie hook_p orphan; /* orphan hook connection */ 80126035Spjd u_char autoSrcAddr; /* always overwrite source address */ 81126035Spjd u_char promisc; /* promiscuous mode enabled */ 82126035Spjd u_long hwassist; /* hardware checksum capabilities */ 83126035Spjd u_int flags; /* flags e.g. really die */ 84126035Spjd}; 85126035Spjdtypedef struct private *priv_p; 8662143Sarchie 87106933Ssam/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 88106933Ssamextern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 89106933Ssamextern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 90106933Ssamextern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 91106933Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 92106933Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 93139903Sglebiusextern void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 94106933Ssam 9562143Sarchie/* Functional hooks called from if_ethersubr.c */ 96106933Ssamstatic void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 97106933Ssamstatic void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 9862143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 9962143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 10062143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 101139903Sglebiusstatic void ng_ether_link_state(struct ifnet *ifp, int state); 10262143Sarchie 10362143Sarchie/* Other functions */ 104131155Sjulianstatic int ng_ether_rcv_lower(node_p node, struct mbuf *m); 105131155Sjulianstatic int ng_ether_rcv_upper(node_p node, struct mbuf *m); 10662143Sarchie 10762143Sarchie/* Netgraph node methods */ 10862143Sarchiestatic ng_constructor_t ng_ether_constructor; 10962143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 11070700Sjulianstatic ng_shutdown_t ng_ether_shutdown; 11162143Sarchiestatic ng_newhook_t ng_ether_newhook; 11269922Sjulianstatic ng_connect_t ng_ether_connect; 11362143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 11462143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 11562143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 11662143Sarchie 11762143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 11862143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 11962143Sarchie { 12062143Sarchie NGM_ETHER_COOKIE, 12162143Sarchie NGM_ETHER_GET_IFNAME, 12262143Sarchie "getifname", 12362143Sarchie NULL, 12462143Sarchie &ng_parse_string_type 12562143Sarchie }, 12662143Sarchie { 12762143Sarchie NGM_ETHER_COOKIE, 12862143Sarchie NGM_ETHER_GET_IFINDEX, 12962143Sarchie "getifindex", 13062143Sarchie NULL, 13162143Sarchie &ng_parse_int32_type 13262143Sarchie }, 13364358Sarchie { 13464358Sarchie NGM_ETHER_COOKIE, 13564358Sarchie NGM_ETHER_GET_ENADDR, 13664358Sarchie "getenaddr", 13764358Sarchie NULL, 138123600Sru &ng_parse_enaddr_type 13964358Sarchie }, 14064358Sarchie { 14164358Sarchie NGM_ETHER_COOKIE, 14264653Sarchie NGM_ETHER_SET_ENADDR, 14364653Sarchie "setenaddr", 144123600Sru &ng_parse_enaddr_type, 14564653Sarchie NULL 14664653Sarchie }, 14764653Sarchie { 14864653Sarchie NGM_ETHER_COOKIE, 14964653Sarchie NGM_ETHER_GET_PROMISC, 15064653Sarchie "getpromisc", 15164653Sarchie NULL, 15264653Sarchie &ng_parse_int32_type 15364653Sarchie }, 15464653Sarchie { 15564653Sarchie NGM_ETHER_COOKIE, 15664358Sarchie NGM_ETHER_SET_PROMISC, 15764358Sarchie "setpromisc", 15864358Sarchie &ng_parse_int32_type, 15964358Sarchie NULL 16064358Sarchie }, 16164358Sarchie { 16264358Sarchie NGM_ETHER_COOKIE, 16364653Sarchie NGM_ETHER_GET_AUTOSRC, 16464653Sarchie "getautosrc", 16564653Sarchie NULL, 16664653Sarchie &ng_parse_int32_type 16764653Sarchie }, 16864653Sarchie { 16964653Sarchie NGM_ETHER_COOKIE, 17064358Sarchie NGM_ETHER_SET_AUTOSRC, 17164358Sarchie "setautosrc", 17264358Sarchie &ng_parse_int32_type, 17364358Sarchie NULL 17464358Sarchie }, 175141721Sglebius { 176141721Sglebius NGM_ETHER_COOKIE, 177141721Sglebius NGM_ETHER_ADD_MULTI, 178141721Sglebius "addmulti", 179141721Sglebius &ng_parse_enaddr_type, 180141721Sglebius NULL 181141721Sglebius }, 182141721Sglebius { 183141721Sglebius NGM_ETHER_COOKIE, 184141721Sglebius NGM_ETHER_DEL_MULTI, 185141721Sglebius "delmulti", 186141721Sglebius &ng_parse_enaddr_type, 187141721Sglebius NULL 188141721Sglebius }, 18962143Sarchie { 0 } 19062143Sarchie}; 19162143Sarchie 19262143Sarchiestatic struct ng_type ng_ether_typestruct = { 193129823Sjulian .version = NG_ABI_VERSION, 194129823Sjulian .name = NG_ETHER_NODE_TYPE, 195129823Sjulian .mod_event = ng_ether_mod_event, 196129823Sjulian .constructor = ng_ether_constructor, 197129823Sjulian .rcvmsg = ng_ether_rcvmsg, 198129823Sjulian .shutdown = ng_ether_shutdown, 199129823Sjulian .newhook = ng_ether_newhook, 200129823Sjulian .connect = ng_ether_connect, 201129823Sjulian .rcvdata = ng_ether_rcvdata, 202129823Sjulian .disconnect = ng_ether_disconnect, 203129823Sjulian .cmdlist = ng_ether_cmdlist, 20462143Sarchie}; 20562143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 20662143Sarchie 20762143Sarchie/****************************************************************** 20862143Sarchie ETHERNET FUNCTION HOOKS 20962143Sarchie******************************************************************/ 21062143Sarchie 21162143Sarchie/* 21262143Sarchie * Handle a packet that has come in on an interface. We get to 21362143Sarchie * look at it here before any upper layer protocols do. 21462143Sarchie * 21562143Sarchie * NOTE: this function will get called at splimp() 21662143Sarchie */ 21762143Sarchiestatic void 218106933Ssamng_ether_input(struct ifnet *ifp, struct mbuf **mp) 21962143Sarchie{ 22062143Sarchie const node_p node = IFP2NG(ifp); 22170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 222129281Sarchie int error; 22362143Sarchie 22462143Sarchie /* If "lower" hook not connected, let packet continue */ 225129281Sarchie if (priv->lower == NULL) 22662143Sarchie return; 227129281Sarchie NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */ 22862143Sarchie} 22962143Sarchie 23062143Sarchie/* 23162143Sarchie * Handle a packet that has come in on an interface, and which 23262143Sarchie * does not match any of our known protocols (an ``orphan''). 23362143Sarchie * 23462143Sarchie * NOTE: this function will get called at splimp() 23562143Sarchie */ 23662143Sarchiestatic void 237106933Ssamng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 23862143Sarchie{ 23962143Sarchie const node_p node = IFP2NG(ifp); 24070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 241129281Sarchie int error; 24262143Sarchie 243129281Sarchie /* If "orphan" hook not connected, discard packet */ 244129281Sarchie if (priv->orphan == NULL) { 24562143Sarchie m_freem(m); 24662143Sarchie return; 24762143Sarchie } 248129281Sarchie NG_SEND_DATA_ONLY(error, priv->orphan, m); 24962143Sarchie} 25062143Sarchie 25162143Sarchie/* 25262143Sarchie * Handle a packet that is going out on an interface. 25362143Sarchie * The Ethernet header is already attached to the mbuf. 25462143Sarchie */ 25562143Sarchiestatic int 25662143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 25762143Sarchie{ 25862143Sarchie const node_p node = IFP2NG(ifp); 25970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 26062143Sarchie int error = 0; 26162143Sarchie 26262143Sarchie /* If "upper" hook not connected, let packet continue */ 26362143Sarchie if (priv->upper == NULL) 26462143Sarchie return (0); 26562143Sarchie 26662143Sarchie /* Send it out "upper" hook */ 26770700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 26862143Sarchie return (error); 26962143Sarchie} 27062143Sarchie 27162143Sarchie/* 27262143Sarchie * A new Ethernet interface has been attached. 27362143Sarchie * Create a new node for it, etc. 27462143Sarchie */ 27562143Sarchiestatic void 27662143Sarchieng_ether_attach(struct ifnet *ifp) 27762143Sarchie{ 27862143Sarchie priv_p priv; 27962143Sarchie node_p node; 28062143Sarchie 28162143Sarchie /* Create node */ 28287599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 28362143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 28462143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 285121816Sbrooks __func__, "create node", ifp->if_xname); 28662143Sarchie return; 28762143Sarchie } 28862143Sarchie 28962143Sarchie /* Allocate private data */ 29068876Sdwmalone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 29162143Sarchie if (priv == NULL) { 29262143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 293121816Sbrooks __func__, "allocate memory", ifp->if_xname); 29470784Sjulian NG_NODE_UNREF(node); 29562143Sarchie return; 29662143Sarchie } 29770784Sjulian NG_NODE_SET_PRIVATE(node, priv); 29862143Sarchie priv->ifp = ifp; 299132780Skan IFP2NG_SET(ifp, node); 30064358Sarchie priv->autoSrcAddr = 1; 30190249Sarchie priv->hwassist = ifp->if_hwassist; 30262143Sarchie 30362143Sarchie /* Try to give the node the same name as the interface */ 304121816Sbrooks if (ng_name_node(node, ifp->if_xname) != 0) { 30562143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 306121816Sbrooks __func__, ifp->if_xname); 30762143Sarchie } 30862143Sarchie} 30962143Sarchie 31062143Sarchie/* 31162143Sarchie * An Ethernet interface is being detached. 31271849Sjulian * REALLY Destroy its node. 31362143Sarchie */ 31462143Sarchiestatic void 31562143Sarchieng_ether_detach(struct ifnet *ifp) 31662143Sarchie{ 31762143Sarchie const node_p node = IFP2NG(ifp); 31871849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 31962143Sarchie 32071849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 32171849Sjulian /* 32271849Sjulian * We can't assume the ifnet is still around when we run shutdown 32371849Sjulian * So zap it now. XXX We HOPE that anything running at this time 32471849Sjulian * handles it (as it should in the non netgraph case). 32571849Sjulian */ 326132780Skan IFP2NG_SET(ifp, NULL); 32771849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 32871849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 32962143Sarchie} 33062143Sarchie 331139903Sglebius/* 332139903Sglebius * Notify graph about link event. 333139903Sglebius * if_link_state_change() has already checked that the state has changed. 334139903Sglebius */ 335139903Sglebiusstatic void 336139903Sglebiusng_ether_link_state(struct ifnet *ifp, int state) 337139903Sglebius{ 338139903Sglebius const node_p node = IFP2NG(ifp); 339139903Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 340139903Sglebius struct ng_mesg *msg; 341139903Sglebius int cmd, dummy_error = 0; 342139903Sglebius 343139903Sglebius if (priv->lower == NULL) 344139903Sglebius return; 345139903Sglebius 346139903Sglebius if (state == LINK_STATE_UP) 347139903Sglebius cmd = NGM_LINK_IS_UP; 348139903Sglebius else if (state == LINK_STATE_DOWN) 349139903Sglebius cmd = NGM_LINK_IS_DOWN; 350139903Sglebius else 351139903Sglebius return; 352139903Sglebius 353139903Sglebius NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT); 354139903Sglebius if (msg != NULL) 355139903Sglebius NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0); 356139903Sglebius} 357139903Sglebius 35862143Sarchie/****************************************************************** 35962143Sarchie NETGRAPH NODE METHODS 36062143Sarchie******************************************************************/ 36162143Sarchie 36262143Sarchie/* 36362143Sarchie * It is not possible or allowable to create a node of this type. 36462143Sarchie * Nodes get created when the interface is attached (or, when 36562143Sarchie * this node type's KLD is loaded). 36662143Sarchie */ 36762143Sarchiestatic int 36870700Sjulianng_ether_constructor(node_p node) 36962143Sarchie{ 37062143Sarchie return (EINVAL); 37162143Sarchie} 37262143Sarchie 37362143Sarchie/* 37462143Sarchie * Check for attaching a new hook. 37562143Sarchie */ 37662143Sarchiestatic int 37762143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 37862143Sarchie{ 37970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 38062143Sarchie hook_p *hookptr; 38162143Sarchie 38262143Sarchie /* Divert hook is an alias for lower */ 38362143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 38462143Sarchie name = NG_ETHER_HOOK_LOWER; 38562143Sarchie 38662143Sarchie /* Which hook? */ 38762143Sarchie if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 38862143Sarchie hookptr = &priv->upper; 389129281Sarchie else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) 39062143Sarchie hookptr = &priv->lower; 391129281Sarchie else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) 392129281Sarchie hookptr = &priv->orphan; 393129281Sarchie else 39462143Sarchie return (EINVAL); 39562143Sarchie 39662143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 39762143Sarchie if (*hookptr != NULL) 39862143Sarchie return (EISCONN); 39962143Sarchie 40090249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 40190249Sarchie if (hookptr == &priv->upper) 40290249Sarchie priv->ifp->if_hwassist = 0; 40390249Sarchie 40462143Sarchie /* OK */ 40562143Sarchie *hookptr = hook; 40662143Sarchie return (0); 40762143Sarchie} 40862143Sarchie 40962143Sarchie/* 41069922Sjulian * Hooks are attached, adjust to force queueing. 41169922Sjulian * We don't really care which hook it is. 41269922Sjulian * they should all be queuing for outgoing data. 41369922Sjulian */ 41469922Sjulianstatic int 41569922Sjulianng_ether_connect(hook_p hook) 41669922Sjulian{ 41770784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 41869922Sjulian return (0); 41969922Sjulian} 42069922Sjulian 42169922Sjulian/* 42262143Sarchie * Receive an incoming control message. 42362143Sarchie */ 42462143Sarchiestatic int 42570700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 42662143Sarchie{ 42770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 42862143Sarchie struct ng_mesg *resp = NULL; 42962143Sarchie int error = 0; 43070700Sjulian struct ng_mesg *msg; 43162143Sarchie 43270700Sjulian NGI_GET_MSG(item, msg); 43362143Sarchie switch (msg->header.typecookie) { 43462143Sarchie case NGM_ETHER_COOKIE: 43562143Sarchie switch (msg->header.cmd) { 43662143Sarchie case NGM_ETHER_GET_IFNAME: 437141195Sru NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 43862143Sarchie if (resp == NULL) { 43962143Sarchie error = ENOMEM; 44062143Sarchie break; 44162143Sarchie } 442141195Sru strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 44362143Sarchie break; 44462143Sarchie case NGM_ETHER_GET_IFINDEX: 44562143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 44662143Sarchie if (resp == NULL) { 44762143Sarchie error = ENOMEM; 44862143Sarchie break; 44962143Sarchie } 45062143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 45162143Sarchie break; 45264358Sarchie case NGM_ETHER_GET_ENADDR: 45364358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 45464358Sarchie if (resp == NULL) { 45564358Sarchie error = ENOMEM; 45664358Sarchie break; 45764358Sarchie } 45864358Sarchie bcopy((IFP2AC(priv->ifp))->ac_enaddr, 45964358Sarchie resp->data, ETHER_ADDR_LEN); 46064358Sarchie break; 46164653Sarchie case NGM_ETHER_SET_ENADDR: 46264653Sarchie { 46364653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 46464653Sarchie error = EINVAL; 46564653Sarchie break; 46664653Sarchie } 46764653Sarchie error = if_setlladdr(priv->ifp, 46864653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 46964653Sarchie break; 47064653Sarchie } 47164653Sarchie case NGM_ETHER_GET_PROMISC: 47264653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 47364653Sarchie if (resp == NULL) { 47464653Sarchie error = ENOMEM; 47564653Sarchie break; 47664653Sarchie } 47764653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 47864653Sarchie break; 47964358Sarchie case NGM_ETHER_SET_PROMISC: 48064358Sarchie { 48164358Sarchie u_char want; 48264358Sarchie 48364358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 48464358Sarchie error = EINVAL; 48564358Sarchie break; 48664358Sarchie } 48764358Sarchie want = !!*((u_int32_t *)msg->data); 48864358Sarchie if (want ^ priv->promisc) { 48964358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 49064358Sarchie break; 49164358Sarchie priv->promisc = want; 49264358Sarchie } 49364358Sarchie break; 49464358Sarchie } 49564653Sarchie case NGM_ETHER_GET_AUTOSRC: 49664653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 49764653Sarchie if (resp == NULL) { 49864653Sarchie error = ENOMEM; 49964653Sarchie break; 50064653Sarchie } 50164653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 50264653Sarchie break; 50364358Sarchie case NGM_ETHER_SET_AUTOSRC: 50464358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 50564358Sarchie error = EINVAL; 50664358Sarchie break; 50764358Sarchie } 50864358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 50964358Sarchie break; 510141721Sglebius case NGM_ETHER_ADD_MULTI: 511141721Sglebius { 512141721Sglebius struct sockaddr_dl sa_dl; 513141721Sglebius struct ifmultiaddr *ifm; 514141721Sglebius 515141721Sglebius if (msg->header.arglen != ETHER_ADDR_LEN) { 516141721Sglebius error = EINVAL; 517141721Sglebius break; 518141721Sglebius } 519141721Sglebius sa_dl.sdl_len = sizeof(struct sockaddr_dl); 520141721Sglebius sa_dl.sdl_family = AF_LINK; 521141721Sglebius sa_dl.sdl_index = 0; 522141721Sglebius sa_dl.sdl_nlen = 0; 523141721Sglebius sa_dl.sdl_alen = 6; 524141721Sglebius sa_dl.sdl_slen = 0; 525141721Sglebius bcopy((void *)msg->data, LLADDR(&sa_dl), 526141721Sglebius ETHER_ADDR_LEN); 527141721Sglebius error = if_addmulti(priv->ifp, 528141721Sglebius (struct sockaddr *)&sa_dl, &ifm); 529141721Sglebius break; 530141721Sglebius } 531141721Sglebius case NGM_ETHER_DEL_MULTI: 532141721Sglebius { 533141721Sglebius struct sockaddr_dl sa_dl; 534141721Sglebius 535141721Sglebius if (msg->header.arglen != ETHER_ADDR_LEN) { 536141721Sglebius error = EINVAL; 537141721Sglebius break; 538141721Sglebius } 539141721Sglebius sa_dl.sdl_len = sizeof(struct sockaddr_dl); 540141721Sglebius sa_dl.sdl_family = AF_LINK; 541141721Sglebius sa_dl.sdl_index = 0; 542141721Sglebius sa_dl.sdl_nlen = 0; 543141721Sglebius sa_dl.sdl_alen = 6; 544141721Sglebius sa_dl.sdl_slen = 0; 545141721Sglebius bcopy((void *)msg->data, LLADDR(&sa_dl), 546141721Sglebius ETHER_ADDR_LEN); 547141721Sglebius error = if_delmulti(priv->ifp, 548141721Sglebius (struct sockaddr *)&sa_dl); 549141721Sglebius break; 550141721Sglebius } 55162143Sarchie default: 55262143Sarchie error = EINVAL; 55362143Sarchie break; 55462143Sarchie } 55562143Sarchie break; 55662143Sarchie default: 55762143Sarchie error = EINVAL; 55862143Sarchie break; 55962143Sarchie } 56070700Sjulian NG_RESPOND_MSG(error, node, item, resp); 56170700Sjulian NG_FREE_MSG(msg); 56262143Sarchie return (error); 56362143Sarchie} 56462143Sarchie 56562143Sarchie/* 56662143Sarchie * Receive data on a hook. 56762143Sarchie */ 56862143Sarchiestatic int 56970700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 57062143Sarchie{ 57170784Sjulian const node_p node = NG_HOOK_NODE(hook); 57270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 57370700Sjulian struct mbuf *m; 57462143Sarchie 57570700Sjulian NGI_GET_M(item, m); 57670700Sjulian NG_FREE_ITEM(item); 577131155Sjulian 578129281Sarchie if (hook == priv->lower || hook == priv->orphan) 579131155Sjulian return ng_ether_rcv_lower(node, m); 58062143Sarchie if (hook == priv->upper) 581131155Sjulian return ng_ether_rcv_upper(node, m); 58287599Sobrien panic("%s: weird hook", __func__); 583129281Sarchie#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */ 584136312Sdes return (0); 58583366Sjulian#endif 58662143Sarchie} 58762143Sarchie 58862143Sarchie/* 589129281Sarchie * Handle an mbuf received on the "lower" or "orphan" hook. 59062143Sarchie */ 59162143Sarchiestatic int 592131155Sjulianng_ether_rcv_lower(node_p node, struct mbuf *m) 59362143Sarchie{ 59470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 59596265Sarchie struct ifnet *const ifp = priv->ifp; 59662143Sarchie 59796265Sarchie /* Check whether interface is ready for packets */ 59896265Sarchie if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 59996265Sarchie NG_FREE_M(m); 60096265Sarchie return (ENETDOWN); 60196265Sarchie } 60296265Sarchie 60362143Sarchie /* Make sure header is fully pulled up */ 60462143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 60570700Sjulian NG_FREE_M(m); 60662143Sarchie return (EINVAL); 60762143Sarchie } 60862143Sarchie if (m->m_len < sizeof(struct ether_header) 60997896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 61062143Sarchie return (ENOBUFS); 61162143Sarchie 61264358Sarchie /* Drop in the MAC address if desired */ 61364358Sarchie if (priv->autoSrcAddr) { 61497896Sarchie 61597896Sarchie /* Make the mbuf writable if it's not already */ 61697896Sarchie if (!M_WRITABLE(m) 61797896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 61897896Sarchie return (ENOBUFS); 61997896Sarchie 62097896Sarchie /* Overwrite source MAC address */ 62196265Sarchie bcopy((IFP2AC(ifp))->ac_enaddr, 62264358Sarchie mtod(m, struct ether_header *)->ether_shost, 62364358Sarchie ETHER_ADDR_LEN); 62464358Sarchie } 62562678Sjulian 62662143Sarchie /* Send it on its way */ 62796265Sarchie return ether_output_frame(ifp, m); 62862143Sarchie} 62962143Sarchie 63062143Sarchie/* 63162143Sarchie * Handle an mbuf received on the "upper" hook. 63262143Sarchie */ 63362143Sarchiestatic int 634131155Sjulianng_ether_rcv_upper(node_p node, struct mbuf *m) 63562143Sarchie{ 63670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 63762143Sarchie 63866061Sjulian m->m_pkthdr.rcvif = priv->ifp; 63962143Sarchie 640136428Sglebius if (BDG_ACTIVE(priv->ifp) ) 641136428Sglebius if ((m = bridge_in_ptr(priv->ifp, m)) == NULL) 642136428Sglebius return (0); 643136428Sglebius 64462143Sarchie /* Route packet back in */ 645106933Ssam ether_demux(priv->ifp, m); 64662143Sarchie return (0); 64762143Sarchie} 64862143Sarchie 64962143Sarchie/* 65071849Sjulian * Shutdown node. This resets the node but does not remove it 65171849Sjulian * unless the REALLY_DIE flag is set. 65262143Sarchie */ 65362143Sarchiestatic int 65470700Sjulianng_ether_shutdown(node_p node) 65562143Sarchie{ 65670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 65764358Sarchie 658132464Sjulian if (node->nd_flags & NGF_REALLY_DIE) { 65971849Sjulian /* 66071849Sjulian * WE came here because the ethernet card is being unloaded, 66171849Sjulian * so stop being persistant. 66271849Sjulian * Actually undo all the things we did on creation. 66371849Sjulian * Assume the ifp has already been freed. 66471849Sjulian */ 66571849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 66671849Sjulian FREE(priv, M_NETGRAPH); 66771849Sjulian NG_NODE_UNREF(node); /* free node itself */ 66871849Sjulian return (0); 66970700Sjulian } 670124269Sgreen if (priv->promisc) { /* disable promiscuous mode */ 671124269Sgreen (void)ifpromisc(priv->ifp, 0); 672124269Sgreen priv->promisc = 0; 673124269Sgreen } 67464358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 675132464Sjulian NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ 676132464Sjulian 67762143Sarchie return (0); 67862143Sarchie} 67962143Sarchie 68062143Sarchie/* 68162143Sarchie * Hook disconnection. 68262143Sarchie */ 68362143Sarchiestatic int 68462143Sarchieng_ether_disconnect(hook_p hook) 68562143Sarchie{ 68670784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 68762143Sarchie 68890249Sarchie if (hook == priv->upper) { 68962143Sarchie priv->upper = NULL; 690124270Sgreen if (priv->ifp != NULL) /* restore h/w csum */ 691124270Sgreen priv->ifp->if_hwassist = priv->hwassist; 692129281Sarchie } else if (hook == priv->lower) 69362143Sarchie priv->lower = NULL; 694129281Sarchie else if (hook == priv->orphan) 695129281Sarchie priv->orphan = NULL; 696129281Sarchie else 69787599Sobrien panic("%s: weird hook", __func__); 69870784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 69970784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 70070784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 70162143Sarchie return (0); 70262143Sarchie} 70362143Sarchie 70462143Sarchie/****************************************************************** 70562143Sarchie INITIALIZATION 70662143Sarchie******************************************************************/ 70762143Sarchie 70862143Sarchie/* 70962143Sarchie * Handle loading and unloading for this node type. 71062143Sarchie */ 71162143Sarchiestatic int 71262143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 71362143Sarchie{ 71462143Sarchie struct ifnet *ifp; 71562143Sarchie int error = 0; 71662143Sarchie int s; 71762143Sarchie 71862143Sarchie s = splnet(); 71962143Sarchie switch (event) { 72062143Sarchie case MOD_LOAD: 72162143Sarchie 72262143Sarchie /* Register function hooks */ 72362143Sarchie if (ng_ether_attach_p != NULL) { 72462143Sarchie error = EEXIST; 72562143Sarchie break; 72662143Sarchie } 72762143Sarchie ng_ether_attach_p = ng_ether_attach; 72862143Sarchie ng_ether_detach_p = ng_ether_detach; 72962143Sarchie ng_ether_output_p = ng_ether_output; 73062143Sarchie ng_ether_input_p = ng_ether_input; 73162143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 732139903Sglebius ng_ether_link_state_p = ng_ether_link_state; 73362143Sarchie 73462143Sarchie /* Create nodes for any already-existing Ethernet interfaces */ 735108172Shsu IFNET_RLOCK(); 73662143Sarchie TAILQ_FOREACH(ifp, &ifnet, if_link) { 73782586Sarchie if (ifp->if_type == IFT_ETHER 73882586Sarchie || ifp->if_type == IFT_L2VLAN) 73962143Sarchie ng_ether_attach(ifp); 74062143Sarchie } 741108172Shsu IFNET_RUNLOCK(); 74262143Sarchie break; 74362143Sarchie 74462143Sarchie case MOD_UNLOAD: 74562143Sarchie 74662143Sarchie /* 74762143Sarchie * Note that the base code won't try to unload us until 74862143Sarchie * all nodes have been removed, and that can't happen 74962143Sarchie * until all Ethernet interfaces are removed. In any 75062143Sarchie * case, we know there are no nodes left if the action 75162143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 75262143Sarchie */ 75362143Sarchie 75462143Sarchie /* Unregister function hooks */ 75562143Sarchie ng_ether_attach_p = NULL; 75662143Sarchie ng_ether_detach_p = NULL; 75762143Sarchie ng_ether_output_p = NULL; 75862143Sarchie ng_ether_input_p = NULL; 75962143Sarchie ng_ether_input_orphan_p = NULL; 760139903Sglebius ng_ether_link_state_p = NULL; 76162143Sarchie break; 76262143Sarchie 76362143Sarchie default: 76462143Sarchie error = EOPNOTSUPP; 76562143Sarchie break; 76662143Sarchie } 76762143Sarchie splx(s); 76862143Sarchie return (error); 76962143Sarchie} 77062143Sarchie 771