ng_ether.c revision 194012
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 194012 2009-06-11 16:50:49Z zec $ 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> 57181803Sbz#include <sys/vimage.h> 5862143Sarchie 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> 65151305Sthompsa#include <net/if_bridgevar.h> 66189106Sbz#include <net/route.h> 67185571Sbz#include <net/vnet.h> 6862143Sarchie 6962143Sarchie#include <netgraph/ng_message.h> 7062143Sarchie#include <netgraph/netgraph.h> 7162143Sarchie#include <netgraph/ng_parse.h> 7262143Sarchie#include <netgraph/ng_ether.h> 7362143Sarchie 74152243Sru#define IFP2NG(ifp) (IFP2AC((ifp))->ac_netgraph) 7562143Sarchie 76191510Szecstatic vnet_attach_fn ng_ether_iattach; 77191510Szec 78191510Szec#ifndef VIMAGE_GLOBALS 79191510Szecstatic vnet_modinfo_t vnet_ng_ether_modinfo = { 80191510Szec .vmi_id = VNET_MOD_NG_ETHER, 81191510Szec .vmi_name = "ng_ether", 82191510Szec .vmi_dependson = VNET_MOD_NETGRAPH, 83191510Szec .vmi_iattach = ng_ether_iattach, 84191510Szec}; 85191510Szec#endif 86191510Szec 87126035Spjd/* Per-node private data */ 88126035Spjdstruct private { 89126035Spjd struct ifnet *ifp; /* associated interface */ 90126035Spjd hook_p upper; /* upper hook connection */ 91129281Sarchie hook_p lower; /* lower hook connection */ 92129281Sarchie hook_p orphan; /* orphan hook connection */ 93126035Spjd u_char autoSrcAddr; /* always overwrite source address */ 94126035Spjd u_char promisc; /* promiscuous mode enabled */ 95126035Spjd u_long hwassist; /* hardware checksum capabilities */ 96126035Spjd u_int flags; /* flags e.g. really die */ 97126035Spjd}; 98126035Spjdtypedef struct private *priv_p; 9962143Sarchie 100106933Ssam/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 101106933Ssamextern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 102106933Ssamextern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 103106933Ssamextern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 104106933Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 105106933Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 106139903Sglebiusextern void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 107106933Ssam 10862143Sarchie/* Functional hooks called from if_ethersubr.c */ 109106933Ssamstatic void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 110106933Ssamstatic void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 11162143Sarchiestatic int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 11262143Sarchiestatic void ng_ether_attach(struct ifnet *ifp); 11362143Sarchiestatic void ng_ether_detach(struct ifnet *ifp); 114139903Sglebiusstatic void ng_ether_link_state(struct ifnet *ifp, int state); 11562143Sarchie 11662143Sarchie/* Other functions */ 117186488Sjulianstatic int ng_ether_rcv_lower(hook_p node, item_p item); 118186488Sjulianstatic int ng_ether_rcv_upper(hook_p node, item_p item); 11962143Sarchie 12062143Sarchie/* Netgraph node methods */ 12162143Sarchiestatic ng_constructor_t ng_ether_constructor; 12262143Sarchiestatic ng_rcvmsg_t ng_ether_rcvmsg; 12370700Sjulianstatic ng_shutdown_t ng_ether_shutdown; 12462143Sarchiestatic ng_newhook_t ng_ether_newhook; 12562143Sarchiestatic ng_rcvdata_t ng_ether_rcvdata; 12662143Sarchiestatic ng_disconnect_t ng_ether_disconnect; 12762143Sarchiestatic int ng_ether_mod_event(module_t mod, int event, void *data); 12862143Sarchie 12962143Sarchie/* List of commands and how to convert arguments to/from ASCII */ 13062143Sarchiestatic const struct ng_cmdlist ng_ether_cmdlist[] = { 13162143Sarchie { 13262143Sarchie NGM_ETHER_COOKIE, 13362143Sarchie NGM_ETHER_GET_IFNAME, 13462143Sarchie "getifname", 13562143Sarchie NULL, 13662143Sarchie &ng_parse_string_type 13762143Sarchie }, 13862143Sarchie { 13962143Sarchie NGM_ETHER_COOKIE, 14062143Sarchie NGM_ETHER_GET_IFINDEX, 14162143Sarchie "getifindex", 14262143Sarchie NULL, 14362143Sarchie &ng_parse_int32_type 14462143Sarchie }, 14564358Sarchie { 14664358Sarchie NGM_ETHER_COOKIE, 14764358Sarchie NGM_ETHER_GET_ENADDR, 14864358Sarchie "getenaddr", 14964358Sarchie NULL, 150123600Sru &ng_parse_enaddr_type 15164358Sarchie }, 15264358Sarchie { 15364358Sarchie NGM_ETHER_COOKIE, 15464653Sarchie NGM_ETHER_SET_ENADDR, 15564653Sarchie "setenaddr", 156123600Sru &ng_parse_enaddr_type, 15764653Sarchie NULL 15864653Sarchie }, 15964653Sarchie { 16064653Sarchie NGM_ETHER_COOKIE, 16164653Sarchie NGM_ETHER_GET_PROMISC, 16264653Sarchie "getpromisc", 16364653Sarchie NULL, 16464653Sarchie &ng_parse_int32_type 16564653Sarchie }, 16664653Sarchie { 16764653Sarchie NGM_ETHER_COOKIE, 16864358Sarchie NGM_ETHER_SET_PROMISC, 16964358Sarchie "setpromisc", 17064358Sarchie &ng_parse_int32_type, 17164358Sarchie NULL 17264358Sarchie }, 17364358Sarchie { 17464358Sarchie NGM_ETHER_COOKIE, 17564653Sarchie NGM_ETHER_GET_AUTOSRC, 17664653Sarchie "getautosrc", 17764653Sarchie NULL, 17864653Sarchie &ng_parse_int32_type 17964653Sarchie }, 18064653Sarchie { 18164653Sarchie NGM_ETHER_COOKIE, 18264358Sarchie NGM_ETHER_SET_AUTOSRC, 18364358Sarchie "setautosrc", 18464358Sarchie &ng_parse_int32_type, 18564358Sarchie NULL 18664358Sarchie }, 187141721Sglebius { 188141721Sglebius NGM_ETHER_COOKIE, 189141721Sglebius NGM_ETHER_ADD_MULTI, 190141721Sglebius "addmulti", 191141721Sglebius &ng_parse_enaddr_type, 192141721Sglebius NULL 193141721Sglebius }, 194141721Sglebius { 195141721Sglebius NGM_ETHER_COOKIE, 196141721Sglebius NGM_ETHER_DEL_MULTI, 197141721Sglebius "delmulti", 198141721Sglebius &ng_parse_enaddr_type, 199141721Sglebius NULL 200141721Sglebius }, 201141910Sglebius { 202141910Sglebius NGM_ETHER_COOKIE, 203141910Sglebius NGM_ETHER_DETACH, 204141910Sglebius "detach", 205141910Sglebius NULL, 206141910Sglebius NULL 207141910Sglebius }, 20862143Sarchie { 0 } 20962143Sarchie}; 21062143Sarchie 21162143Sarchiestatic struct ng_type ng_ether_typestruct = { 212129823Sjulian .version = NG_ABI_VERSION, 213129823Sjulian .name = NG_ETHER_NODE_TYPE, 214129823Sjulian .mod_event = ng_ether_mod_event, 215129823Sjulian .constructor = ng_ether_constructor, 216129823Sjulian .rcvmsg = ng_ether_rcvmsg, 217129823Sjulian .shutdown = ng_ether_shutdown, 218129823Sjulian .newhook = ng_ether_newhook, 219129823Sjulian .rcvdata = ng_ether_rcvdata, 220129823Sjulian .disconnect = ng_ether_disconnect, 221129823Sjulian .cmdlist = ng_ether_cmdlist, 22262143Sarchie}; 22362143SarchieNETGRAPH_INIT(ether, &ng_ether_typestruct); 22462143Sarchie 22562143Sarchie/****************************************************************** 22662143Sarchie ETHERNET FUNCTION HOOKS 22762143Sarchie******************************************************************/ 22862143Sarchie 22962143Sarchie/* 23062143Sarchie * Handle a packet that has come in on an interface. We get to 23162143Sarchie * look at it here before any upper layer protocols do. 23262143Sarchie * 23362143Sarchie * NOTE: this function will get called at splimp() 23462143Sarchie */ 23562143Sarchiestatic void 236106933Ssamng_ether_input(struct ifnet *ifp, struct mbuf **mp) 23762143Sarchie{ 23862143Sarchie const node_p node = IFP2NG(ifp); 23970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 240129281Sarchie int error; 24162143Sarchie 24262143Sarchie /* If "lower" hook not connected, let packet continue */ 243129281Sarchie if (priv->lower == NULL) 24462143Sarchie return; 245129281Sarchie NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */ 24662143Sarchie} 24762143Sarchie 24862143Sarchie/* 24962143Sarchie * Handle a packet that has come in on an interface, and which 25062143Sarchie * does not match any of our known protocols (an ``orphan''). 25162143Sarchie * 25262143Sarchie * NOTE: this function will get called at splimp() 25362143Sarchie */ 25462143Sarchiestatic void 255106933Ssamng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 25662143Sarchie{ 25762143Sarchie const node_p node = IFP2NG(ifp); 25870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 259129281Sarchie int error; 26062143Sarchie 261129281Sarchie /* If "orphan" hook not connected, discard packet */ 262129281Sarchie if (priv->orphan == NULL) { 26362143Sarchie m_freem(m); 26462143Sarchie return; 26562143Sarchie } 266129281Sarchie NG_SEND_DATA_ONLY(error, priv->orphan, m); 26762143Sarchie} 26862143Sarchie 26962143Sarchie/* 27062143Sarchie * Handle a packet that is going out on an interface. 27162143Sarchie * The Ethernet header is already attached to the mbuf. 27262143Sarchie */ 27362143Sarchiestatic int 27462143Sarchieng_ether_output(struct ifnet *ifp, struct mbuf **mp) 27562143Sarchie{ 27662143Sarchie const node_p node = IFP2NG(ifp); 27770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 27862143Sarchie int error = 0; 27962143Sarchie 28062143Sarchie /* If "upper" hook not connected, let packet continue */ 28162143Sarchie if (priv->upper == NULL) 28262143Sarchie return (0); 28362143Sarchie 28462143Sarchie /* Send it out "upper" hook */ 285194012Szec NG_OUTBOUND_THREAD_REF(); 28670700Sjulian NG_SEND_DATA_ONLY(error, priv->upper, *mp); 287194012Szec NG_OUTBOUND_THREAD_UNREF(); 28862143Sarchie return (error); 28962143Sarchie} 29062143Sarchie 29162143Sarchie/* 29262143Sarchie * A new Ethernet interface has been attached. 29362143Sarchie * Create a new node for it, etc. 29462143Sarchie */ 29562143Sarchiestatic void 29662143Sarchieng_ether_attach(struct ifnet *ifp) 29762143Sarchie{ 29862143Sarchie priv_p priv; 29962143Sarchie node_p node; 30062143Sarchie 301191510Szec /* 302191510Szec * Do not create / attach an ether node to this ifnet if 303191510Szec * a netgraph node with the same name already exists. 304191510Szec * This should prevent ether nodes to become attached to 305191510Szec * eiface nodes, which may be problematic due to naming 306191510Szec * clashes. 307191510Szec */ 308191510Szec if ((node = ng_name2noderef(NULL, ifp->if_xname)) != NULL) { 309191510Szec NG_NODE_UNREF(node); 310191510Szec return; 311191510Szec } 312191510Szec 31362143Sarchie /* Create node */ 31487599Sobrien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 31562143Sarchie if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 31662143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 317121816Sbrooks __func__, "create node", ifp->if_xname); 31862143Sarchie return; 31962143Sarchie } 32062143Sarchie 32162143Sarchie /* Allocate private data */ 322184205Sdes priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 32362143Sarchie if (priv == NULL) { 32462143Sarchie log(LOG_ERR, "%s: can't %s for %s\n", 325121816Sbrooks __func__, "allocate memory", ifp->if_xname); 32670784Sjulian NG_NODE_UNREF(node); 32762143Sarchie return; 32862143Sarchie } 32970784Sjulian NG_NODE_SET_PRIVATE(node, priv); 33062143Sarchie priv->ifp = ifp; 331152243Sru IFP2NG(ifp) = node; 33290249Sarchie priv->hwassist = ifp->if_hwassist; 33362143Sarchie 33462143Sarchie /* Try to give the node the same name as the interface */ 335121816Sbrooks if (ng_name_node(node, ifp->if_xname) != 0) { 33662143Sarchie log(LOG_WARNING, "%s: can't name node %s\n", 337121816Sbrooks __func__, ifp->if_xname); 33862143Sarchie } 33962143Sarchie} 34062143Sarchie 34162143Sarchie/* 34262143Sarchie * An Ethernet interface is being detached. 34371849Sjulian * REALLY Destroy its node. 34462143Sarchie */ 34562143Sarchiestatic void 34662143Sarchieng_ether_detach(struct ifnet *ifp) 34762143Sarchie{ 34862143Sarchie const node_p node = IFP2NG(ifp); 34971849Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 35062143Sarchie 35171849Sjulian NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 35271849Sjulian /* 35371849Sjulian * We can't assume the ifnet is still around when we run shutdown 35471849Sjulian * So zap it now. XXX We HOPE that anything running at this time 35571849Sjulian * handles it (as it should in the non netgraph case). 35671849Sjulian */ 357152243Sru IFP2NG(ifp) = NULL; 35871849Sjulian priv->ifp = NULL; /* XXX race if interrupted an output packet */ 35971849Sjulian ng_rmnode_self(node); /* remove all netgraph parts */ 36062143Sarchie} 36162143Sarchie 362139903Sglebius/* 363139903Sglebius * Notify graph about link event. 364139903Sglebius * if_link_state_change() has already checked that the state has changed. 365139903Sglebius */ 366139903Sglebiusstatic void 367139903Sglebiusng_ether_link_state(struct ifnet *ifp, int state) 368139903Sglebius{ 369139903Sglebius const node_p node = IFP2NG(ifp); 370139903Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 371139903Sglebius struct ng_mesg *msg; 372139903Sglebius int cmd, dummy_error = 0; 373139903Sglebius 374139903Sglebius if (priv->lower == NULL) 375139903Sglebius return; 376139903Sglebius 377139903Sglebius if (state == LINK_STATE_UP) 378139903Sglebius cmd = NGM_LINK_IS_UP; 379139903Sglebius else if (state == LINK_STATE_DOWN) 380139903Sglebius cmd = NGM_LINK_IS_DOWN; 381139903Sglebius else 382139903Sglebius return; 383139903Sglebius 384139903Sglebius NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT); 385139903Sglebius if (msg != NULL) 386139903Sglebius NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0); 387139903Sglebius} 388139903Sglebius 38962143Sarchie/****************************************************************** 39062143Sarchie NETGRAPH NODE METHODS 39162143Sarchie******************************************************************/ 39262143Sarchie 39362143Sarchie/* 39462143Sarchie * It is not possible or allowable to create a node of this type. 39562143Sarchie * Nodes get created when the interface is attached (or, when 39662143Sarchie * this node type's KLD is loaded). 39762143Sarchie */ 39862143Sarchiestatic int 39970700Sjulianng_ether_constructor(node_p node) 40062143Sarchie{ 40162143Sarchie return (EINVAL); 40262143Sarchie} 40362143Sarchie 40462143Sarchie/* 40562143Sarchie * Check for attaching a new hook. 40662143Sarchie */ 40762143Sarchiestatic int 40862143Sarchieng_ether_newhook(node_p node, hook_p hook, const char *name) 40962143Sarchie{ 41070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 41162143Sarchie hook_p *hookptr; 41262143Sarchie 41362143Sarchie /* Divert hook is an alias for lower */ 41462143Sarchie if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 41562143Sarchie name = NG_ETHER_HOOK_LOWER; 41662143Sarchie 41762143Sarchie /* Which hook? */ 418186488Sjulian if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) { 41962143Sarchie hookptr = &priv->upper; 420186488Sjulian NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_upper); 421194012Szec NG_HOOK_SET_TO_INBOUND(hook); 422186488Sjulian } else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 42362143Sarchie hookptr = &priv->lower; 424186488Sjulian NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_lower); 425186488Sjulian } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 426129281Sarchie hookptr = &priv->orphan; 427186488Sjulian NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_lower); 428186488Sjulian } else 42962143Sarchie return (EINVAL); 43062143Sarchie 43162143Sarchie /* Check if already connected (shouldn't be, but doesn't hurt) */ 43262143Sarchie if (*hookptr != NULL) 43362143Sarchie return (EISCONN); 43462143Sarchie 43590249Sarchie /* Disable hardware checksums while 'upper' hook is connected */ 43690249Sarchie if (hookptr == &priv->upper) 43790249Sarchie priv->ifp->if_hwassist = 0; 43890249Sarchie 43962143Sarchie /* OK */ 44062143Sarchie *hookptr = hook; 44162143Sarchie return (0); 44262143Sarchie} 44362143Sarchie 44462143Sarchie/* 44562143Sarchie * Receive an incoming control message. 44662143Sarchie */ 44762143Sarchiestatic int 44870700Sjulianng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 44962143Sarchie{ 45070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 45162143Sarchie struct ng_mesg *resp = NULL; 45262143Sarchie int error = 0; 45370700Sjulian struct ng_mesg *msg; 45462143Sarchie 45570700Sjulian NGI_GET_MSG(item, msg); 45662143Sarchie switch (msg->header.typecookie) { 45762143Sarchie case NGM_ETHER_COOKIE: 45862143Sarchie switch (msg->header.cmd) { 45962143Sarchie case NGM_ETHER_GET_IFNAME: 460141195Sru NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 46162143Sarchie if (resp == NULL) { 46262143Sarchie error = ENOMEM; 46362143Sarchie break; 46462143Sarchie } 465141195Sru strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 46662143Sarchie break; 46762143Sarchie case NGM_ETHER_GET_IFINDEX: 46862143Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 46962143Sarchie if (resp == NULL) { 47062143Sarchie error = ENOMEM; 47162143Sarchie break; 47262143Sarchie } 47362143Sarchie *((u_int32_t *)resp->data) = priv->ifp->if_index; 47462143Sarchie break; 47564358Sarchie case NGM_ETHER_GET_ENADDR: 47664358Sarchie NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 47764358Sarchie if (resp == NULL) { 47864358Sarchie error = ENOMEM; 47964358Sarchie break; 48064358Sarchie } 481152315Sru bcopy(IF_LLADDR(priv->ifp), 48264358Sarchie resp->data, ETHER_ADDR_LEN); 48364358Sarchie break; 48464653Sarchie case NGM_ETHER_SET_ENADDR: 48564653Sarchie { 48664653Sarchie if (msg->header.arglen != ETHER_ADDR_LEN) { 48764653Sarchie error = EINVAL; 48864653Sarchie break; 48964653Sarchie } 49064653Sarchie error = if_setlladdr(priv->ifp, 49164653Sarchie (u_char *)msg->data, ETHER_ADDR_LEN); 49264653Sarchie break; 49364653Sarchie } 49464653Sarchie case NGM_ETHER_GET_PROMISC: 49564653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 49664653Sarchie if (resp == NULL) { 49764653Sarchie error = ENOMEM; 49864653Sarchie break; 49964653Sarchie } 50064653Sarchie *((u_int32_t *)resp->data) = priv->promisc; 50164653Sarchie break; 50264358Sarchie case NGM_ETHER_SET_PROMISC: 50364358Sarchie { 50464358Sarchie u_char want; 50564358Sarchie 50664358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 50764358Sarchie error = EINVAL; 50864358Sarchie break; 50964358Sarchie } 51064358Sarchie want = !!*((u_int32_t *)msg->data); 51164358Sarchie if (want ^ priv->promisc) { 51264358Sarchie if ((error = ifpromisc(priv->ifp, want)) != 0) 51364358Sarchie break; 51464358Sarchie priv->promisc = want; 51564358Sarchie } 51664358Sarchie break; 51764358Sarchie } 51864653Sarchie case NGM_ETHER_GET_AUTOSRC: 51964653Sarchie NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 52064653Sarchie if (resp == NULL) { 52164653Sarchie error = ENOMEM; 52264653Sarchie break; 52364653Sarchie } 52464653Sarchie *((u_int32_t *)resp->data) = priv->autoSrcAddr; 52564653Sarchie break; 52664358Sarchie case NGM_ETHER_SET_AUTOSRC: 52764358Sarchie if (msg->header.arglen != sizeof(u_int32_t)) { 52864358Sarchie error = EINVAL; 52964358Sarchie break; 53064358Sarchie } 53164358Sarchie priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 53264358Sarchie break; 533141721Sglebius case NGM_ETHER_ADD_MULTI: 534141721Sglebius { 535141721Sglebius struct sockaddr_dl sa_dl; 536167729Sbms struct ifmultiaddr *ifma; 537141721Sglebius 538141721Sglebius if (msg->header.arglen != ETHER_ADDR_LEN) { 539141721Sglebius error = EINVAL; 540141721Sglebius break; 541141721Sglebius } 542141755Sglebius bzero(&sa_dl, sizeof(struct sockaddr_dl)); 543141721Sglebius sa_dl.sdl_len = sizeof(struct sockaddr_dl); 544141721Sglebius sa_dl.sdl_family = AF_LINK; 545141755Sglebius sa_dl.sdl_alen = ETHER_ADDR_LEN; 546141721Sglebius bcopy((void *)msg->data, LLADDR(&sa_dl), 547141721Sglebius ETHER_ADDR_LEN); 548167729Sbms /* 549167729Sbms * Netgraph is only permitted to join groups once 550167729Sbms * via the if_addmulti() KPI, because it cannot hold 551167729Sbms * struct ifmultiaddr * between calls. It may also 552167729Sbms * lose a race while we check if the membership 553167729Sbms * already exists. 554167729Sbms */ 555167729Sbms IF_ADDR_LOCK(priv->ifp); 556167729Sbms ifma = if_findmulti(priv->ifp, 557167729Sbms (struct sockaddr *)&sa_dl); 558167729Sbms IF_ADDR_UNLOCK(priv->ifp); 559167729Sbms if (ifma != NULL) { 560167729Sbms error = EADDRINUSE; 561167729Sbms } else { 562167729Sbms error = if_addmulti(priv->ifp, 563167729Sbms (struct sockaddr *)&sa_dl, &ifma); 564167729Sbms } 565141721Sglebius break; 566141721Sglebius } 567141721Sglebius case NGM_ETHER_DEL_MULTI: 568141721Sglebius { 569141721Sglebius struct sockaddr_dl sa_dl; 570141721Sglebius 571141721Sglebius if (msg->header.arglen != ETHER_ADDR_LEN) { 572141721Sglebius error = EINVAL; 573141721Sglebius break; 574141721Sglebius } 575141755Sglebius bzero(&sa_dl, sizeof(struct sockaddr_dl)); 576141721Sglebius sa_dl.sdl_len = sizeof(struct sockaddr_dl); 577141721Sglebius sa_dl.sdl_family = AF_LINK; 578141755Sglebius sa_dl.sdl_alen = ETHER_ADDR_LEN; 579141721Sglebius bcopy((void *)msg->data, LLADDR(&sa_dl), 580141721Sglebius ETHER_ADDR_LEN); 581141721Sglebius error = if_delmulti(priv->ifp, 582141721Sglebius (struct sockaddr *)&sa_dl); 583141721Sglebius break; 584141721Sglebius } 585141910Sglebius case NGM_ETHER_DETACH: 586141910Sglebius ng_ether_detach(priv->ifp); 587141910Sglebius break; 58862143Sarchie default: 58962143Sarchie error = EINVAL; 59062143Sarchie break; 59162143Sarchie } 59262143Sarchie break; 59362143Sarchie default: 59462143Sarchie error = EINVAL; 59562143Sarchie break; 59662143Sarchie } 59770700Sjulian NG_RESPOND_MSG(error, node, item, resp); 59870700Sjulian NG_FREE_MSG(msg); 59962143Sarchie return (error); 60062143Sarchie} 60162143Sarchie 60262143Sarchie/* 60362143Sarchie * Receive data on a hook. 604186488Sjulian * Since we use per-hook recveive methods this should never be called. 60562143Sarchie */ 60662143Sarchiestatic int 60770700Sjulianng_ether_rcvdata(hook_p hook, item_p item) 60862143Sarchie{ 60970700Sjulian NG_FREE_ITEM(item); 610131155Sjulian 61187599Sobrien panic("%s: weird hook", __func__); 612129281Sarchie#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */ 613136312Sdes return (0); 61483366Sjulian#endif 61562143Sarchie} 61662143Sarchie 61762143Sarchie/* 618129281Sarchie * Handle an mbuf received on the "lower" or "orphan" hook. 61962143Sarchie */ 62062143Sarchiestatic int 621186488Sjulianng_ether_rcv_lower(hook_p hook, item_p item) 62262143Sarchie{ 623186488Sjulian struct mbuf *m; 624186488Sjulian const node_p node = NG_HOOK_NODE(hook); 62570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 62696265Sarchie struct ifnet *const ifp = priv->ifp; 62762143Sarchie 628186488Sjulian NGI_GET_M(item, m); 629186488Sjulian NG_FREE_ITEM(item); 630186488Sjulian 63196265Sarchie /* Check whether interface is ready for packets */ 632186488Sjulian 633148887Srwatson if (!((ifp->if_flags & IFF_UP) && 634148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 63596265Sarchie NG_FREE_M(m); 63696265Sarchie return (ENETDOWN); 63796265Sarchie } 63896265Sarchie 63962143Sarchie /* Make sure header is fully pulled up */ 64062143Sarchie if (m->m_pkthdr.len < sizeof(struct ether_header)) { 64170700Sjulian NG_FREE_M(m); 64262143Sarchie return (EINVAL); 64362143Sarchie } 64462143Sarchie if (m->m_len < sizeof(struct ether_header) 64597896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 64662143Sarchie return (ENOBUFS); 64762143Sarchie 64864358Sarchie /* Drop in the MAC address if desired */ 64964358Sarchie if (priv->autoSrcAddr) { 65097896Sarchie 65197896Sarchie /* Make the mbuf writable if it's not already */ 65297896Sarchie if (!M_WRITABLE(m) 65397896Sarchie && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 65497896Sarchie return (ENOBUFS); 65597896Sarchie 65697896Sarchie /* Overwrite source MAC address */ 657152315Sru bcopy(IF_LLADDR(ifp), 65864358Sarchie mtod(m, struct ether_header *)->ether_shost, 65964358Sarchie ETHER_ADDR_LEN); 66064358Sarchie } 66162678Sjulian 66262143Sarchie /* Send it on its way */ 66396265Sarchie return ether_output_frame(ifp, m); 66462143Sarchie} 66562143Sarchie 66662143Sarchie/* 66762143Sarchie * Handle an mbuf received on the "upper" hook. 66862143Sarchie */ 66962143Sarchiestatic int 670186488Sjulianng_ether_rcv_upper(hook_p hook, item_p item) 67162143Sarchie{ 672186488Sjulian struct mbuf *m; 673186488Sjulian const node_p node = NG_HOOK_NODE(hook); 67470784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 675151063Sglebius struct ifnet *ifp = priv->ifp; 67662143Sarchie 677186488Sjulian NGI_GET_M(item, m); 678186488Sjulian NG_FREE_ITEM(item); 679186488Sjulian 680152001Sru /* Check length and pull off header */ 681152001Sru if (m->m_pkthdr.len < sizeof(struct ether_header)) { 682152001Sru NG_FREE_M(m); 683152001Sru return (EINVAL); 684152001Sru } 685152001Sru if (m->m_len < sizeof(struct ether_header) && 686152001Sru (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 687152001Sru return (ENOBUFS); 688152001Sru 689151063Sglebius m->m_pkthdr.rcvif = ifp; 69062143Sarchie 691151305Sthompsa /* Pass the packet to the bridge, it may come back to us */ 692151063Sglebius if (ifp->if_bridge) { 693151305Sthompsa BRIDGE_INPUT(ifp, m); 694151063Sglebius if (m == NULL) 695151063Sglebius return (0); 696151063Sglebius } 697151063Sglebius 69862143Sarchie /* Route packet back in */ 699151305Sthompsa ether_demux(ifp, m); 70062143Sarchie return (0); 70162143Sarchie} 70262143Sarchie 70362143Sarchie/* 70471849Sjulian * Shutdown node. This resets the node but does not remove it 70571849Sjulian * unless the REALLY_DIE flag is set. 70662143Sarchie */ 70762143Sarchiestatic int 70870700Sjulianng_ether_shutdown(node_p node) 70962143Sarchie{ 71070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 71164358Sarchie 712132464Sjulian if (node->nd_flags & NGF_REALLY_DIE) { 71371849Sjulian /* 71471849Sjulian * WE came here because the ethernet card is being unloaded, 71571849Sjulian * so stop being persistant. 71671849Sjulian * Actually undo all the things we did on creation. 71771849Sjulian * Assume the ifp has already been freed. 71871849Sjulian */ 71971849Sjulian NG_NODE_SET_PRIVATE(node, NULL); 720184205Sdes free(priv, M_NETGRAPH); 72171849Sjulian NG_NODE_UNREF(node); /* free node itself */ 72271849Sjulian return (0); 72370700Sjulian } 724124269Sgreen if (priv->promisc) { /* disable promiscuous mode */ 725124269Sgreen (void)ifpromisc(priv->ifp, 0); 726124269Sgreen priv->promisc = 0; 727124269Sgreen } 72864358Sarchie priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 729132464Sjulian NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ 730132464Sjulian 73162143Sarchie return (0); 73262143Sarchie} 73362143Sarchie 73462143Sarchie/* 73562143Sarchie * Hook disconnection. 73662143Sarchie */ 73762143Sarchiestatic int 73862143Sarchieng_ether_disconnect(hook_p hook) 73962143Sarchie{ 74070784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 74162143Sarchie 74290249Sarchie if (hook == priv->upper) { 74362143Sarchie priv->upper = NULL; 744124270Sgreen if (priv->ifp != NULL) /* restore h/w csum */ 745124270Sgreen priv->ifp->if_hwassist = priv->hwassist; 746129281Sarchie } else if (hook == priv->lower) 74762143Sarchie priv->lower = NULL; 748129281Sarchie else if (hook == priv->orphan) 749129281Sarchie priv->orphan = NULL; 750129281Sarchie else 75187599Sobrien panic("%s: weird hook", __func__); 75270784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 75370784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 75470784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 75562143Sarchie return (0); 75662143Sarchie} 75762143Sarchie 75862143Sarchie/****************************************************************** 75962143Sarchie INITIALIZATION 76062143Sarchie******************************************************************/ 76162143Sarchie 76262143Sarchie/* 76362143Sarchie * Handle loading and unloading for this node type. 76462143Sarchie */ 76562143Sarchiestatic int 76662143Sarchieng_ether_mod_event(module_t mod, int event, void *data) 76762143Sarchie{ 76862143Sarchie int error = 0; 76962143Sarchie int s; 77062143Sarchie 77162143Sarchie s = splnet(); 77262143Sarchie switch (event) { 77362143Sarchie case MOD_LOAD: 77462143Sarchie 77562143Sarchie /* Register function hooks */ 77662143Sarchie if (ng_ether_attach_p != NULL) { 77762143Sarchie error = EEXIST; 77862143Sarchie break; 77962143Sarchie } 78062143Sarchie ng_ether_attach_p = ng_ether_attach; 78162143Sarchie ng_ether_detach_p = ng_ether_detach; 78262143Sarchie ng_ether_output_p = ng_ether_output; 78362143Sarchie ng_ether_input_p = ng_ether_input; 78462143Sarchie ng_ether_input_orphan_p = ng_ether_input_orphan; 785139903Sglebius ng_ether_link_state_p = ng_ether_link_state; 78662143Sarchie 787191510Szec#ifndef VIMAGE_GLOBALS 788191510Szec vnet_mod_register(&vnet_ng_ether_modinfo); 789191510Szec#else 790191510Szec error = ng_ether_iattach(NULL); 791191510Szec#endif 79262143Sarchie break; 79362143Sarchie 79462143Sarchie case MOD_UNLOAD: 79562143Sarchie 79662143Sarchie /* 79762143Sarchie * Note that the base code won't try to unload us until 79862143Sarchie * all nodes have been removed, and that can't happen 79962143Sarchie * until all Ethernet interfaces are removed. In any 80062143Sarchie * case, we know there are no nodes left if the action 80162143Sarchie * is MOD_UNLOAD, so there's no need to detach any nodes. 80262143Sarchie */ 80362143Sarchie 804191510Szec#ifndef VIMAGE_GLOBALS 805191510Szec vnet_mod_deregister(&vnet_ng_ether_modinfo); 806191510Szec#endif 807191510Szec 80862143Sarchie /* Unregister function hooks */ 80962143Sarchie ng_ether_attach_p = NULL; 81062143Sarchie ng_ether_detach_p = NULL; 81162143Sarchie ng_ether_output_p = NULL; 81262143Sarchie ng_ether_input_p = NULL; 81362143Sarchie ng_ether_input_orphan_p = NULL; 814139903Sglebius ng_ether_link_state_p = NULL; 81562143Sarchie break; 81662143Sarchie 81762143Sarchie default: 81862143Sarchie error = EOPNOTSUPP; 81962143Sarchie break; 82062143Sarchie } 82162143Sarchie splx(s); 82262143Sarchie return (error); 82362143Sarchie} 82462143Sarchie 825191510Szecstatic int ng_ether_iattach(const void *unused) 826191510Szec{ 827191510Szec INIT_VNET_NET(curvnet); 828191510Szec struct ifnet *ifp; 829191510Szec 830191510Szec /* Create nodes for any already-existing Ethernet interfaces. */ 831191510Szec IFNET_RLOCK(); 832191510Szec TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 833191510Szec if (ifp->if_type == IFT_ETHER 834191510Szec || ifp->if_type == IFT_L2VLAN) 835191510Szec ng_ether_attach(ifp); 836191510Szec } 837191510Szec IFNET_RUNLOCK(); 838191510Szec 839191510Szec return (0); 840191510Szec} 841