xref: /dflybsd-src/sys/netgraph7/ether/ng_ether.c (revision 55d4a94aed9a1540970ded7fa631d15f77ef41e5)
10147868eSNuno Antunes 
20147868eSNuno Antunes /*
30147868eSNuno Antunes  * ng_ether.c
40147868eSNuno Antunes  */
50147868eSNuno Antunes 
60147868eSNuno Antunes /*-
70147868eSNuno Antunes  * Copyright (c) 1996-2000 Whistle Communications, Inc.
80147868eSNuno Antunes  * All rights reserved.
90147868eSNuno Antunes  *
100147868eSNuno Antunes  * Subject to the following obligations and disclaimer of warranty, use and
110147868eSNuno Antunes  * redistribution of this software, in source or object code forms, with or
120147868eSNuno Antunes  * without modifications are expressly permitted by Whistle Communications;
130147868eSNuno Antunes  * provided, however, that:
140147868eSNuno Antunes  * 1. Any and all reproductions of the source or object code must include the
150147868eSNuno Antunes  *    copyright notice above and the following disclaimer of warranties; and
160147868eSNuno Antunes  * 2. No rights are granted, in any manner or form, to use Whistle
170147868eSNuno Antunes  *    Communications, Inc. trademarks, including the mark "WHISTLE
180147868eSNuno Antunes  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
190147868eSNuno Antunes  *    such appears in the above copyright notice or in the software.
200147868eSNuno Antunes  *
210147868eSNuno Antunes  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
220147868eSNuno Antunes  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
230147868eSNuno Antunes  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
240147868eSNuno Antunes  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
250147868eSNuno Antunes  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
260147868eSNuno Antunes  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
270147868eSNuno Antunes  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
280147868eSNuno Antunes  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
290147868eSNuno Antunes  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
300147868eSNuno Antunes  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
310147868eSNuno Antunes  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
320147868eSNuno Antunes  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
330147868eSNuno Antunes  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
340147868eSNuno Antunes  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
350147868eSNuno Antunes  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
360147868eSNuno Antunes  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
370147868eSNuno Antunes  * OF SUCH DAMAGE.
380147868eSNuno Antunes  *
390147868eSNuno Antunes  * Authors: Archie Cobbs <archie@freebsd.org>
400147868eSNuno Antunes  *	    Julian Elischer <julian@freebsd.org>
410147868eSNuno Antunes  *
420147868eSNuno Antunes  * $FreeBSD: src/sys/netgraph/ng_ether.c,v 1.62 2007/03/20 00:36:10 bms Exp $
430147868eSNuno Antunes  */
440147868eSNuno Antunes 
450147868eSNuno Antunes /*
460147868eSNuno Antunes  * ng_ether(4) netgraph node type
470147868eSNuno Antunes  */
480147868eSNuno Antunes 
490147868eSNuno Antunes #include <sys/param.h>
500147868eSNuno Antunes #include <sys/systm.h>
510147868eSNuno Antunes #include <sys/kernel.h>
520147868eSNuno Antunes #include <sys/malloc.h>
530147868eSNuno Antunes #include <sys/mbuf.h>
540147868eSNuno Antunes #include <sys/errno.h>
550147868eSNuno Antunes #include <sys/syslog.h>
560147868eSNuno Antunes #include <sys/socket.h>
570147868eSNuno Antunes 
580147868eSNuno Antunes #include <net/if.h>
590147868eSNuno Antunes #include <net/if_dl.h>
600147868eSNuno Antunes #include <net/if_types.h>
610147868eSNuno Antunes #include <net/if_arp.h>
620147868eSNuno Antunes #include <net/if_var.h>
630147868eSNuno Antunes #include <net/ethernet.h>
640147868eSNuno Antunes #include <net/bridge/if_bridgevar.h>
650147868eSNuno Antunes 
660147868eSNuno Antunes #include <netgraph7/ng_message.h>
670147868eSNuno Antunes #include <netgraph7/netgraph.h>
680147868eSNuno Antunes #include <netgraph7/ng_parse.h>
690147868eSNuno Antunes #include "ng_ether.h"
700147868eSNuno Antunes 
710147868eSNuno Antunes #define IFP2AC(ifp)	((struct arpcom *)ifp)
720147868eSNuno Antunes #define IFP2NG(ifp)	(IFP2AC((ifp))->ac_netgraph)
730147868eSNuno Antunes 
740147868eSNuno Antunes /* Per-node private data */
750147868eSNuno Antunes struct private {
760147868eSNuno Antunes 	struct ifnet	*ifp;		/* associated interface */
770147868eSNuno Antunes 	hook_p		upper;		/* upper hook connection */
780147868eSNuno Antunes 	hook_p		lower;		/* lower hook connection */
790147868eSNuno Antunes 	hook_p		orphan;		/* orphan hook connection */
800147868eSNuno Antunes 	u_char		autoSrcAddr;	/* always overwrite source address */
810147868eSNuno Antunes 	u_char		promisc;	/* promiscuous mode enabled */
820147868eSNuno Antunes 	u_long		hwassist;	/* hardware checksum capabilities */
830147868eSNuno Antunes 	u_int		flags;		/* flags e.g. really die */
840147868eSNuno Antunes };
850147868eSNuno Antunes typedef struct private *priv_p;
860147868eSNuno Antunes 
870147868eSNuno Antunes /* Functional hooks called from if_ethersubr.c */
880147868eSNuno Antunes static void	ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
890147868eSNuno Antunes static void	ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
900147868eSNuno Antunes static int	ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
910147868eSNuno Antunes static void	ng_ether_attach(struct ifnet *ifp);
920147868eSNuno Antunes static void	ng_ether_detach(struct ifnet *ifp);
930147868eSNuno Antunes #if 0
940147868eSNuno Antunes static void	ng_ether_link_state(struct ifnet *ifp, int state);
950147868eSNuno Antunes #endif
960147868eSNuno Antunes 
970147868eSNuno Antunes /* Other functions */
980147868eSNuno Antunes static int	ng_ether_rcv_lower(node_p node, struct mbuf *m);
990147868eSNuno Antunes static int	ng_ether_rcv_upper(node_p node, struct mbuf *m);
1000147868eSNuno Antunes 
1010147868eSNuno Antunes /* Netgraph node methods */
1020147868eSNuno Antunes static ng_constructor_t	ng_ether_constructor;
1030147868eSNuno Antunes static ng_rcvmsg_t	ng_ether_rcvmsg;
1040147868eSNuno Antunes static ng_shutdown_t	ng_ether_shutdown;
1050147868eSNuno Antunes static ng_newhook_t	ng_ether_newhook;
1060147868eSNuno Antunes static ng_rcvdata_t	ng_ether_rcvdata;
1070147868eSNuno Antunes static ng_disconnect_t	ng_ether_disconnect;
1080147868eSNuno Antunes static int		ng_ether_mod_event(module_t mod, int event, void *data);
1090147868eSNuno Antunes 
1100147868eSNuno Antunes /* List of commands and how to convert arguments to/from ASCII */
1110147868eSNuno Antunes static const struct ng_cmdlist ng_ether_cmdlist[] = {
1120147868eSNuno Antunes 	{
1130147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1140147868eSNuno Antunes 	  NGM_ETHER_GET_IFNAME,
1150147868eSNuno Antunes 	  "getifname",
1160147868eSNuno Antunes 	  NULL,
1170147868eSNuno Antunes 	  &ng_parse_string_type
1180147868eSNuno Antunes 	},
1190147868eSNuno Antunes 	{
1200147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1210147868eSNuno Antunes 	  NGM_ETHER_GET_IFINDEX,
1220147868eSNuno Antunes 	  "getifindex",
1230147868eSNuno Antunes 	  NULL,
1240147868eSNuno Antunes 	  &ng_parse_int32_type
1250147868eSNuno Antunes 	},
1260147868eSNuno Antunes 	{
1270147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1280147868eSNuno Antunes 	  NGM_ETHER_GET_ENADDR,
1290147868eSNuno Antunes 	  "getenaddr",
1300147868eSNuno Antunes 	  NULL,
1310147868eSNuno Antunes 	  &ng_parse_enaddr_type
1320147868eSNuno Antunes 	},
1330147868eSNuno Antunes 	{
1340147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1350147868eSNuno Antunes 	  NGM_ETHER_SET_ENADDR,
1360147868eSNuno Antunes 	  "setenaddr",
1370147868eSNuno Antunes 	  &ng_parse_enaddr_type,
1380147868eSNuno Antunes 	  NULL
1390147868eSNuno Antunes 	},
1400147868eSNuno Antunes 	{
1410147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1420147868eSNuno Antunes 	  NGM_ETHER_GET_PROMISC,
1430147868eSNuno Antunes 	  "getpromisc",
1440147868eSNuno Antunes 	  NULL,
1450147868eSNuno Antunes 	  &ng_parse_int32_type
1460147868eSNuno Antunes 	},
1470147868eSNuno Antunes 	{
1480147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1490147868eSNuno Antunes 	  NGM_ETHER_SET_PROMISC,
1500147868eSNuno Antunes 	  "setpromisc",
1510147868eSNuno Antunes 	  &ng_parse_int32_type,
1520147868eSNuno Antunes 	  NULL
1530147868eSNuno Antunes 	},
1540147868eSNuno Antunes 	{
1550147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1560147868eSNuno Antunes 	  NGM_ETHER_GET_AUTOSRC,
1570147868eSNuno Antunes 	  "getautosrc",
1580147868eSNuno Antunes 	  NULL,
1590147868eSNuno Antunes 	  &ng_parse_int32_type
1600147868eSNuno Antunes 	},
1610147868eSNuno Antunes 	{
1620147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1630147868eSNuno Antunes 	  NGM_ETHER_SET_AUTOSRC,
1640147868eSNuno Antunes 	  "setautosrc",
1650147868eSNuno Antunes 	  &ng_parse_int32_type,
1660147868eSNuno Antunes 	  NULL
1670147868eSNuno Antunes 	},
1680147868eSNuno Antunes 	{
1690147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1700147868eSNuno Antunes 	  NGM_ETHER_ADD_MULTI,
1710147868eSNuno Antunes 	  "addmulti",
1720147868eSNuno Antunes 	  &ng_parse_enaddr_type,
1730147868eSNuno Antunes 	  NULL
1740147868eSNuno Antunes 	},
1750147868eSNuno Antunes 	{
1760147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1770147868eSNuno Antunes 	  NGM_ETHER_DEL_MULTI,
1780147868eSNuno Antunes 	  "delmulti",
1790147868eSNuno Antunes 	  &ng_parse_enaddr_type,
1800147868eSNuno Antunes 	  NULL
1810147868eSNuno Antunes 	},
1820147868eSNuno Antunes 	{
1830147868eSNuno Antunes 	  NGM_ETHER_COOKIE,
1840147868eSNuno Antunes 	  NGM_ETHER_DETACH,
1850147868eSNuno Antunes 	  "detach",
1860147868eSNuno Antunes 	  NULL,
1870147868eSNuno Antunes 	  NULL
1880147868eSNuno Antunes 	},
1890147868eSNuno Antunes 	{ 0 }
1900147868eSNuno Antunes };
1910147868eSNuno Antunes 
1920147868eSNuno Antunes static struct ng_type ng_ether_typestruct = {
1930147868eSNuno Antunes 	.version =	NG_ABI_VERSION,
1940147868eSNuno Antunes 	.name =		NG_ETHER_NODE_TYPE,
1950147868eSNuno Antunes 	.mod_event =	ng_ether_mod_event,
1960147868eSNuno Antunes 	.constructor =	ng_ether_constructor,
1970147868eSNuno Antunes 	.rcvmsg =	ng_ether_rcvmsg,
1980147868eSNuno Antunes 	.shutdown =	ng_ether_shutdown,
1990147868eSNuno Antunes 	.newhook =	ng_ether_newhook,
2000147868eSNuno Antunes 	.rcvdata =	ng_ether_rcvdata,
2010147868eSNuno Antunes 	.disconnect =	ng_ether_disconnect,
2020147868eSNuno Antunes 	.cmdlist =	ng_ether_cmdlist,
2030147868eSNuno Antunes };
2040147868eSNuno Antunes NETGRAPH_INIT(ether, &ng_ether_typestruct);
2050147868eSNuno Antunes 
2060147868eSNuno Antunes /******************************************************************
2070147868eSNuno Antunes 		    ETHERNET FUNCTION HOOKS
2080147868eSNuno Antunes ******************************************************************/
2090147868eSNuno Antunes 
2100147868eSNuno Antunes /*
2110147868eSNuno Antunes  * Handle a packet that has come in on an interface. We get to
2120147868eSNuno Antunes  * look at it here before any upper layer protocols do.
2130147868eSNuno Antunes  *
2140147868eSNuno Antunes  * NOTE: this function will get called at splimp()
2150147868eSNuno Antunes  */
2160147868eSNuno Antunes static void
ng_ether_input(struct ifnet * ifp,struct mbuf ** mp)2170147868eSNuno Antunes ng_ether_input(struct ifnet *ifp, struct mbuf **mp)
2180147868eSNuno Antunes {
2190147868eSNuno Antunes 	const node_p node = IFP2NG(ifp);
2200147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
2210147868eSNuno Antunes 	int error;
2220147868eSNuno Antunes 
2230147868eSNuno Antunes 	/* If "lower" hook not connected, let packet continue */
2240147868eSNuno Antunes 	if (priv->lower == NULL)
2250147868eSNuno Antunes 		return;
2260147868eSNuno Antunes 	NG_SEND_DATA_ONLY(error, priv->lower, *mp);	/* sets *mp = NULL */
2270147868eSNuno Antunes }
2280147868eSNuno Antunes 
2290147868eSNuno Antunes /*
2300147868eSNuno Antunes  * Handle a packet that has come in on an interface, and which
2310147868eSNuno Antunes  * does not match any of our known protocols (an ``orphan'').
2320147868eSNuno Antunes  *
2330147868eSNuno Antunes  * NOTE: this function will get called at splimp()
2340147868eSNuno Antunes  */
2350147868eSNuno Antunes static void
ng_ether_input_orphan(struct ifnet * ifp,struct mbuf * m)2360147868eSNuno Antunes ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m)
2370147868eSNuno Antunes {
2380147868eSNuno Antunes 	const node_p node = IFP2NG(ifp);
2390147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
2400147868eSNuno Antunes 	int error;
2410147868eSNuno Antunes 
2420147868eSNuno Antunes 	/* If "orphan" hook not connected, discard packet */
2430147868eSNuno Antunes 	if (priv->orphan == NULL) {
2440147868eSNuno Antunes 		m_freem(m);
2450147868eSNuno Antunes 		return;
2460147868eSNuno Antunes 	}
2470147868eSNuno Antunes 	NG_SEND_DATA_ONLY(error, priv->orphan, m);
2480147868eSNuno Antunes }
2490147868eSNuno Antunes 
2500147868eSNuno Antunes /*
2510147868eSNuno Antunes  * Handle a packet that is going out on an interface.
2520147868eSNuno Antunes  * The Ethernet header is already attached to the mbuf.
2530147868eSNuno Antunes  */
2540147868eSNuno Antunes static int
ng_ether_output(struct ifnet * ifp,struct mbuf ** mp)2550147868eSNuno Antunes ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
2560147868eSNuno Antunes {
2570147868eSNuno Antunes 	const node_p node = IFP2NG(ifp);
2580147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
2590147868eSNuno Antunes 	int error = 0;
2600147868eSNuno Antunes 
2610147868eSNuno Antunes 	/* If "upper" hook not connected, let packet continue */
2620147868eSNuno Antunes 	if (priv->upper == NULL)
2630147868eSNuno Antunes 		return (0);
2640147868eSNuno Antunes 
2650147868eSNuno Antunes 	/* Send it out "upper" hook */
2660147868eSNuno Antunes 	NG_SEND_DATA_ONLY(error, priv->upper, *mp);
2670147868eSNuno Antunes 	return (error);
2680147868eSNuno Antunes }
2690147868eSNuno Antunes 
2700147868eSNuno Antunes /*
2710147868eSNuno Antunes  * A new Ethernet interface has been attached.
2720147868eSNuno Antunes  * Create a new node for it, etc.
2730147868eSNuno Antunes  */
2740147868eSNuno Antunes static void
ng_ether_attach(struct ifnet * ifp)2750147868eSNuno Antunes ng_ether_attach(struct ifnet *ifp)
2760147868eSNuno Antunes {
2770147868eSNuno Antunes 	priv_p priv;
2780147868eSNuno Antunes 	node_p node;
2790147868eSNuno Antunes 
2800147868eSNuno Antunes 	/* Create node */
2810147868eSNuno Antunes 	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
2820147868eSNuno Antunes 	if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
2830147868eSNuno Antunes 		log(LOG_ERR, "%s: can't %s for %s\n",
2840147868eSNuno Antunes 		    __func__, "create node", ifp->if_xname);
2850147868eSNuno Antunes 		return;
2860147868eSNuno Antunes 	}
2870147868eSNuno Antunes 
2880147868eSNuno Antunes 	/* Allocate private data */
2890147868eSNuno Antunes 	priv = kmalloc(sizeof(*priv), M_NETGRAPH,
2900147868eSNuno Antunes 		       M_WAITOK | M_NULLOK | M_ZERO);
2910147868eSNuno Antunes 	if (priv == NULL) {
2920147868eSNuno Antunes 		log(LOG_ERR, "%s: can't %s for %s\n",
2930147868eSNuno Antunes 		    __func__, "allocate memory", ifp->if_xname);
2940147868eSNuno Antunes 		NG_NODE_UNREF(node);
2950147868eSNuno Antunes 		return;
2960147868eSNuno Antunes 	}
2970147868eSNuno Antunes 	NG_NODE_SET_PRIVATE(node, priv);
2980147868eSNuno Antunes 	priv->ifp = ifp;
2990147868eSNuno Antunes 	IFP2NG(ifp) = node;
3000147868eSNuno Antunes 	priv->hwassist = ifp->if_hwassist;
3010147868eSNuno Antunes 
3020147868eSNuno Antunes 	/* Try to give the node the same name as the interface */
3030147868eSNuno Antunes 	if (ng_name_node(node, ifp->if_xname) != 0) {
3040147868eSNuno Antunes 		log(LOG_WARNING, "%s: can't name node %s\n",
3050147868eSNuno Antunes 		    __func__, ifp->if_xname);
3060147868eSNuno Antunes 	}
3070147868eSNuno Antunes }
3080147868eSNuno Antunes 
3090147868eSNuno Antunes /*
3100147868eSNuno Antunes  * An Ethernet interface is being detached.
3110147868eSNuno Antunes  * REALLY Destroy its node.
3120147868eSNuno Antunes  */
3130147868eSNuno Antunes static void
ng_ether_detach(struct ifnet * ifp)3140147868eSNuno Antunes ng_ether_detach(struct ifnet *ifp)
3150147868eSNuno Antunes {
3160147868eSNuno Antunes 	const node_p node = IFP2NG(ifp);
3170147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
3180147868eSNuno Antunes 
3190147868eSNuno Antunes 	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
3200147868eSNuno Antunes 	/*
3210147868eSNuno Antunes 	 * We can't assume the ifnet is still around when we run shutdown
3220147868eSNuno Antunes 	 * So zap it now. XXX We HOPE that anything running at this time
3230147868eSNuno Antunes 	 * handles it (as it should in the non netgraph case).
3240147868eSNuno Antunes 	 */
3250147868eSNuno Antunes 	IFP2NG(ifp) = NULL;
3260147868eSNuno Antunes 	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
3270147868eSNuno Antunes 	ng_rmnode_self(node);		/* remove all netgraph parts */
3280147868eSNuno Antunes }
3290147868eSNuno Antunes 
3300147868eSNuno Antunes #if 0
3310147868eSNuno Antunes /*
3320147868eSNuno Antunes  * Notify graph about link event.
3330147868eSNuno Antunes  * if_link_state_change() has already checked that the state has changed.
3340147868eSNuno Antunes  */
3350147868eSNuno Antunes static void
3360147868eSNuno Antunes ng_ether_link_state(struct ifnet *ifp, int state)
3370147868eSNuno Antunes {
3380147868eSNuno Antunes 	const node_p node = IFP2NG(ifp);
3390147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
3400147868eSNuno Antunes 	struct ng_mesg *msg;
3410147868eSNuno Antunes 	int cmd, dummy_error = 0;
3420147868eSNuno Antunes 
3430147868eSNuno Antunes 	if (priv->lower == NULL)
3440147868eSNuno Antunes                 return;
3450147868eSNuno Antunes 
3460147868eSNuno Antunes 	if (state == LINK_STATE_UP)
3470147868eSNuno Antunes 		cmd = NGM_LINK_IS_UP;
3480147868eSNuno Antunes 	else if (state == LINK_STATE_DOWN)
3490147868eSNuno Antunes 		cmd = NGM_LINK_IS_DOWN;
3500147868eSNuno Antunes 	else
3510147868eSNuno Antunes 		return;
3520147868eSNuno Antunes 
3530147868eSNuno Antunes 	NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
3540147868eSNuno Antunes 	if (msg != NULL)
3550147868eSNuno Antunes 		NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0);
3560147868eSNuno Antunes }
3570147868eSNuno Antunes #endif
3580147868eSNuno Antunes /******************************************************************
3590147868eSNuno Antunes 		    NETGRAPH NODE METHODS
3600147868eSNuno Antunes ******************************************************************/
3610147868eSNuno Antunes 
3620147868eSNuno Antunes /*
3630147868eSNuno Antunes  * It is not possible or allowable to create a node of this type.
3640147868eSNuno Antunes  * Nodes get created when the interface is attached (or, when
3650147868eSNuno Antunes  * this node type's KLD is loaded).
3660147868eSNuno Antunes  */
3670147868eSNuno Antunes static int
ng_ether_constructor(node_p node)3680147868eSNuno Antunes ng_ether_constructor(node_p node)
3690147868eSNuno Antunes {
3700147868eSNuno Antunes 	return (EINVAL);
3710147868eSNuno Antunes }
3720147868eSNuno Antunes 
3730147868eSNuno Antunes /*
3740147868eSNuno Antunes  * Check for attaching a new hook.
3750147868eSNuno Antunes  */
3760147868eSNuno Antunes static	int
ng_ether_newhook(node_p node,hook_p hook,const char * name)3770147868eSNuno Antunes ng_ether_newhook(node_p node, hook_p hook, const char *name)
3780147868eSNuno Antunes {
3790147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
3800147868eSNuno Antunes 	hook_p *hookptr;
3810147868eSNuno Antunes 
3820147868eSNuno Antunes 	/* Divert hook is an alias for lower */
3830147868eSNuno Antunes 	if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
3840147868eSNuno Antunes 		name = NG_ETHER_HOOK_LOWER;
3850147868eSNuno Antunes 
3860147868eSNuno Antunes 	/* Which hook? */
3870147868eSNuno Antunes 	if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
3880147868eSNuno Antunes 		hookptr = &priv->upper;
3890147868eSNuno Antunes 	else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0)
3900147868eSNuno Antunes 		hookptr = &priv->lower;
3910147868eSNuno Antunes 	else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0)
3920147868eSNuno Antunes 		hookptr = &priv->orphan;
3930147868eSNuno Antunes 	else
3940147868eSNuno Antunes 		return (EINVAL);
3950147868eSNuno Antunes 
3960147868eSNuno Antunes 	/* Check if already connected (shouldn't be, but doesn't hurt) */
3970147868eSNuno Antunes 	if (*hookptr != NULL)
3980147868eSNuno Antunes 		return (EISCONN);
3990147868eSNuno Antunes 
4000147868eSNuno Antunes 	/* Disable hardware checksums while 'upper' hook is connected */
4010147868eSNuno Antunes 	if (hookptr == &priv->upper)
4020147868eSNuno Antunes 		priv->ifp->if_hwassist = 0;
4030147868eSNuno Antunes 
4040147868eSNuno Antunes 	/* OK */
4050147868eSNuno Antunes 	*hookptr = hook;
4060147868eSNuno Antunes 	return (0);
4070147868eSNuno Antunes }
4080147868eSNuno Antunes 
4090147868eSNuno Antunes /*
4100147868eSNuno Antunes  * Receive an incoming control message.
4110147868eSNuno Antunes  */
4120147868eSNuno Antunes static int
ng_ether_rcvmsg(node_p node,item_p item,hook_p lasthook)4130147868eSNuno Antunes ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
4140147868eSNuno Antunes {
4150147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
4160147868eSNuno Antunes 	struct ng_mesg *resp = NULL;
4170147868eSNuno Antunes 	int error = 0;
4180147868eSNuno Antunes 	struct ng_mesg *msg;
4190147868eSNuno Antunes 
4200147868eSNuno Antunes 	NGI_GET_MSG(item, msg);
4210147868eSNuno Antunes 	switch (msg->header.typecookie) {
4220147868eSNuno Antunes 	case NGM_ETHER_COOKIE:
4230147868eSNuno Antunes 		switch (msg->header.cmd) {
4240147868eSNuno Antunes 		case NGM_ETHER_GET_IFNAME:
4250147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK);
4260147868eSNuno Antunes 			if (resp == NULL) {
4270147868eSNuno Antunes 				error = ENOMEM;
4280147868eSNuno Antunes 				break;
4290147868eSNuno Antunes 			}
4300147868eSNuno Antunes 			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
4310147868eSNuno Antunes 			break;
4320147868eSNuno Antunes 		case NGM_ETHER_GET_IFINDEX:
4330147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
4340147868eSNuno Antunes 			if (resp == NULL) {
4350147868eSNuno Antunes 				error = ENOMEM;
4360147868eSNuno Antunes 				break;
4370147868eSNuno Antunes 			}
4380147868eSNuno Antunes 			*((u_int32_t *)resp->data) = priv->ifp->if_index;
4390147868eSNuno Antunes 			break;
4400147868eSNuno Antunes 		case NGM_ETHER_GET_ENADDR:
4410147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_WAITOK | M_NULLOK);
4420147868eSNuno Antunes 			if (resp == NULL) {
4430147868eSNuno Antunes 				error = ENOMEM;
4440147868eSNuno Antunes 				break;
4450147868eSNuno Antunes 			}
4460147868eSNuno Antunes 			bcopy(IF_LLADDR(priv->ifp),
4470147868eSNuno Antunes 			    resp->data, ETHER_ADDR_LEN);
4480147868eSNuno Antunes 			break;
4490147868eSNuno Antunes 		case NGM_ETHER_SET_ENADDR:
4500147868eSNuno Antunes 		    {
4510147868eSNuno Antunes 			if (msg->header.arglen != ETHER_ADDR_LEN) {
4520147868eSNuno Antunes 				error = EINVAL;
4530147868eSNuno Antunes 				break;
4540147868eSNuno Antunes 			}
4550147868eSNuno Antunes 			error = if_setlladdr(priv->ifp,
4560147868eSNuno Antunes 			    (u_char *)msg->data, ETHER_ADDR_LEN);
4570147868eSNuno Antunes 			break;
4580147868eSNuno Antunes 		    }
4590147868eSNuno Antunes 		case NGM_ETHER_GET_PROMISC:
4600147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
4610147868eSNuno Antunes 			if (resp == NULL) {
4620147868eSNuno Antunes 				error = ENOMEM;
4630147868eSNuno Antunes 				break;
4640147868eSNuno Antunes 			}
4650147868eSNuno Antunes 			*((u_int32_t *)resp->data) = priv->promisc;
4660147868eSNuno Antunes 			break;
4670147868eSNuno Antunes 		case NGM_ETHER_SET_PROMISC:
4680147868eSNuno Antunes 		    {
4690147868eSNuno Antunes 			u_char want;
4700147868eSNuno Antunes 
4710147868eSNuno Antunes 			if (msg->header.arglen != sizeof(u_int32_t)) {
4720147868eSNuno Antunes 				error = EINVAL;
4730147868eSNuno Antunes 				break;
4740147868eSNuno Antunes 			}
4750147868eSNuno Antunes 			want = !!*((u_int32_t *)msg->data);
4760147868eSNuno Antunes 			if (want ^ priv->promisc) {
4770147868eSNuno Antunes 				if ((error = ifpromisc(priv->ifp, want)) != 0)
4780147868eSNuno Antunes 					break;
4790147868eSNuno Antunes 				priv->promisc = want;
4800147868eSNuno Antunes 			}
4810147868eSNuno Antunes 			break;
4820147868eSNuno Antunes 		    }
4830147868eSNuno Antunes 		case NGM_ETHER_GET_AUTOSRC:
4840147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
4850147868eSNuno Antunes 			if (resp == NULL) {
4860147868eSNuno Antunes 				error = ENOMEM;
4870147868eSNuno Antunes 				break;
4880147868eSNuno Antunes 			}
4890147868eSNuno Antunes 			*((u_int32_t *)resp->data) = priv->autoSrcAddr;
4900147868eSNuno Antunes 			break;
4910147868eSNuno Antunes 		case NGM_ETHER_SET_AUTOSRC:
4920147868eSNuno Antunes 			if (msg->header.arglen != sizeof(u_int32_t)) {
4930147868eSNuno Antunes 				error = EINVAL;
4940147868eSNuno Antunes 				break;
4950147868eSNuno Antunes 			}
4960147868eSNuno Antunes 			priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
4970147868eSNuno Antunes 			break;
4980147868eSNuno Antunes #if 0
4990147868eSNuno Antunes 		case NGM_ETHER_ADD_MULTI:
5000147868eSNuno Antunes 		    {
5010147868eSNuno Antunes 			struct sockaddr_dl sa_dl;
5020147868eSNuno Antunes 			struct ifmultiaddr *ifma;
5030147868eSNuno Antunes 
5040147868eSNuno Antunes 			if (msg->header.arglen != ETHER_ADDR_LEN) {
5050147868eSNuno Antunes 				error = EINVAL;
5060147868eSNuno Antunes 				break;
5070147868eSNuno Antunes 			}
5080147868eSNuno Antunes 			bzero(&sa_dl, sizeof(struct sockaddr_dl));
5090147868eSNuno Antunes 			sa_dl.sdl_len = sizeof(struct sockaddr_dl);
5100147868eSNuno Antunes 			sa_dl.sdl_family = AF_LINK;
5110147868eSNuno Antunes 			sa_dl.sdl_alen = ETHER_ADDR_LEN;
5120147868eSNuno Antunes 			bcopy((void *)msg->data, LLADDR(&sa_dl),
5130147868eSNuno Antunes 			    ETHER_ADDR_LEN);
5140147868eSNuno Antunes 			/*
5150147868eSNuno Antunes 			 * Netgraph is only permitted to join groups once
5160147868eSNuno Antunes 			 * via the if_addmulti() KPI, because it cannot hold
5170147868eSNuno Antunes 			 * struct ifmultiaddr * between calls. It may also
5180147868eSNuno Antunes 			 * lose a race while we check if the membership
5190147868eSNuno Antunes 			 * already exists.
5200147868eSNuno Antunes 			 */
5210147868eSNuno Antunes 			IF_ADDR_LOCK(priv->ifp);
5220147868eSNuno Antunes 			ifma = if_findmulti(priv->ifp,
5230147868eSNuno Antunes 			    (struct sockaddr *)&sa_dl);
5240147868eSNuno Antunes 			IF_ADDR_UNLOCK(priv->ifp);
5250147868eSNuno Antunes 			if (ifma != NULL) {
5260147868eSNuno Antunes 				error = EADDRINUSE;
5270147868eSNuno Antunes 			} else {
5280147868eSNuno Antunes 				error = if_addmulti(priv->ifp,
5290147868eSNuno Antunes 				    (struct sockaddr *)&sa_dl, &ifma);
5300147868eSNuno Antunes 			}
5310147868eSNuno Antunes 			break;
5320147868eSNuno Antunes 		    }
5330147868eSNuno Antunes #endif
5340147868eSNuno Antunes 		case NGM_ETHER_DEL_MULTI:
5350147868eSNuno Antunes 		    {
5360147868eSNuno Antunes 			struct sockaddr_dl sa_dl;
5370147868eSNuno Antunes 
5380147868eSNuno Antunes 			if (msg->header.arglen != ETHER_ADDR_LEN) {
5390147868eSNuno Antunes 				error = EINVAL;
5400147868eSNuno Antunes 				break;
5410147868eSNuno Antunes 			}
5420147868eSNuno Antunes 			bzero(&sa_dl, sizeof(struct sockaddr_dl));
5430147868eSNuno Antunes 			sa_dl.sdl_len = sizeof(struct sockaddr_dl);
5440147868eSNuno Antunes 			sa_dl.sdl_family = AF_LINK;
5450147868eSNuno Antunes 			sa_dl.sdl_alen = ETHER_ADDR_LEN;
5460147868eSNuno Antunes 			bcopy((void *)msg->data, LLADDR(&sa_dl),
5470147868eSNuno Antunes 			    ETHER_ADDR_LEN);
5480147868eSNuno Antunes 			error = if_delmulti(priv->ifp,
5490147868eSNuno Antunes 			    (struct sockaddr *)&sa_dl);
5500147868eSNuno Antunes 			break;
5510147868eSNuno Antunes 		    }
5520147868eSNuno Antunes 		case NGM_ETHER_DETACH:
5530147868eSNuno Antunes 			ng_ether_detach(priv->ifp);
5540147868eSNuno Antunes 			break;
5550147868eSNuno Antunes 		default:
5560147868eSNuno Antunes 			error = EINVAL;
5570147868eSNuno Antunes 			break;
5580147868eSNuno Antunes 		}
5590147868eSNuno Antunes 		break;
5600147868eSNuno Antunes 	default:
5610147868eSNuno Antunes 		error = EINVAL;
5620147868eSNuno Antunes 		break;
5630147868eSNuno Antunes 	}
5640147868eSNuno Antunes 	NG_RESPOND_MSG(error, node, item, resp);
5650147868eSNuno Antunes 	NG_FREE_MSG(msg);
5660147868eSNuno Antunes 	return (error);
5670147868eSNuno Antunes }
5680147868eSNuno Antunes 
5690147868eSNuno Antunes /*
5700147868eSNuno Antunes  * Receive data on a hook.
5710147868eSNuno Antunes  */
5720147868eSNuno Antunes static int
ng_ether_rcvdata(hook_p hook,item_p item)5730147868eSNuno Antunes ng_ether_rcvdata(hook_p hook, item_p item)
5740147868eSNuno Antunes {
5750147868eSNuno Antunes 	const node_p node = NG_HOOK_NODE(hook);
5760147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
5770147868eSNuno Antunes 	struct mbuf *m;
5780147868eSNuno Antunes 
5790147868eSNuno Antunes 	NGI_GET_M(item, m);
5800147868eSNuno Antunes 	NG_FREE_ITEM(item);
5810147868eSNuno Antunes 
5820147868eSNuno Antunes 	if (hook == priv->lower || hook == priv->orphan)
5830147868eSNuno Antunes 		return ng_ether_rcv_lower(node, m);
5840147868eSNuno Antunes 	if (hook == priv->upper)
5850147868eSNuno Antunes 		return ng_ether_rcv_upper(node, m);
5860147868eSNuno Antunes 	panic("%s: weird hook", __func__);
5870147868eSNuno Antunes #ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */
5880147868eSNuno Antunes 	return (0);
5890147868eSNuno Antunes #endif
5900147868eSNuno Antunes }
5910147868eSNuno Antunes 
5920147868eSNuno Antunes /*
5930147868eSNuno Antunes  * Handle an mbuf received on the "lower" or "orphan" hook.
5940147868eSNuno Antunes  */
5950147868eSNuno Antunes static int
ng_ether_rcv_lower(node_p node,struct mbuf * m)5960147868eSNuno Antunes ng_ether_rcv_lower(node_p node, struct mbuf *m)
5970147868eSNuno Antunes {
5980147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
5990147868eSNuno Antunes  	struct ifnet *const ifp = priv->ifp;
6000147868eSNuno Antunes 
6010147868eSNuno Antunes 	/* Check whether interface is ready for packets */
6020147868eSNuno Antunes 	if (!((ifp->if_flags & IFF_UP) &&
6030147868eSNuno Antunes 	    (ifp->if_flags & IFF_RUNNING))) {
6040147868eSNuno Antunes 		NG_FREE_M(m);
6050147868eSNuno Antunes 		return (ENETDOWN);
6060147868eSNuno Antunes 	}
6070147868eSNuno Antunes 
6080147868eSNuno Antunes 	/* Make sure header is fully pulled up */
6090147868eSNuno Antunes 	if (m->m_pkthdr.len < sizeof(struct ether_header)) {
6100147868eSNuno Antunes 		NG_FREE_M(m);
6110147868eSNuno Antunes 		return (EINVAL);
6120147868eSNuno Antunes 	}
6130147868eSNuno Antunes 	if (m->m_len < sizeof(struct ether_header)
6140147868eSNuno Antunes 	    && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
6150147868eSNuno Antunes 		return (ENOBUFS);
6160147868eSNuno Antunes 
6170147868eSNuno Antunes 	/* Drop in the MAC address if desired */
6180147868eSNuno Antunes 	if (priv->autoSrcAddr) {
6190147868eSNuno Antunes 
6200147868eSNuno Antunes 		/* Make the mbuf writable if it's not already */
6210147868eSNuno Antunes 		if (!M_WRITABLE(m)
6220147868eSNuno Antunes 		    && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
6230147868eSNuno Antunes 			return (ENOBUFS);
6240147868eSNuno Antunes 
6250147868eSNuno Antunes 		/* Overwrite source MAC address */
6260147868eSNuno Antunes 		bcopy(IF_LLADDR(ifp),
6270147868eSNuno Antunes 		    mtod(m, struct ether_header *)->ether_shost,
6280147868eSNuno Antunes 		    ETHER_ADDR_LEN);
6290147868eSNuno Antunes 	}
6300147868eSNuno Antunes 
6310147868eSNuno Antunes 	/* Send it on its way */
6320147868eSNuno Antunes 	return ether_output_frame(ifp, m);
6330147868eSNuno Antunes }
6340147868eSNuno Antunes 
6350147868eSNuno Antunes /*
6360147868eSNuno Antunes  * Handle an mbuf received on the "upper" hook.
6370147868eSNuno Antunes  */
6380147868eSNuno Antunes extern	struct mbuf *bridge_input_p(struct ifnet *, struct mbuf *);
6390147868eSNuno Antunes static int
ng_ether_rcv_upper(node_p node,struct mbuf * m)6400147868eSNuno Antunes ng_ether_rcv_upper(node_p node, struct mbuf *m)
6410147868eSNuno Antunes {
6420147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
6430147868eSNuno Antunes 	struct ifnet *ifp = priv->ifp;
6440147868eSNuno Antunes 
6450147868eSNuno Antunes 	/* Check length and pull off header */
6460147868eSNuno Antunes 	if (m->m_pkthdr.len < sizeof(struct ether_header)) {
6470147868eSNuno Antunes 		NG_FREE_M(m);
6480147868eSNuno Antunes 		return (EINVAL);
6490147868eSNuno Antunes 	}
6500147868eSNuno Antunes 	if (m->m_len < sizeof(struct ether_header) &&
6510147868eSNuno Antunes 	    (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
6520147868eSNuno Antunes 		return (ENOBUFS);
6530147868eSNuno Antunes 
6540147868eSNuno Antunes 	m->m_pkthdr.rcvif = ifp;
6550147868eSNuno Antunes 
6560147868eSNuno Antunes 	/* Pass the packet to the bridge, it may come back to us */
6570147868eSNuno Antunes 	if (ifp->if_bridge) {
6580147868eSNuno Antunes 		bridge_input_p(ifp, m);
6590147868eSNuno Antunes 		if (m == NULL)
6600147868eSNuno Antunes 			return (0);
6610147868eSNuno Antunes 	}
6620147868eSNuno Antunes 
6630147868eSNuno Antunes 	/* Route packet back in */
6640147868eSNuno Antunes 	ether_demux_oncpu(ifp, m);
6650147868eSNuno Antunes 	return (0);
6660147868eSNuno Antunes }
6670147868eSNuno Antunes 
6680147868eSNuno Antunes /*
6690147868eSNuno Antunes  * Shutdown node. This resets the node but does not remove it
6700147868eSNuno Antunes  * unless the REALLY_DIE flag is set.
6710147868eSNuno Antunes  */
6720147868eSNuno Antunes static int
ng_ether_shutdown(node_p node)6730147868eSNuno Antunes ng_ether_shutdown(node_p node)
6740147868eSNuno Antunes {
6750147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
6760147868eSNuno Antunes 
6770147868eSNuno Antunes 	if (node->nd_flags & NGF_REALLY_DIE) {
6780147868eSNuno Antunes 		/*
6790147868eSNuno Antunes 		 * WE came here because the ethernet card is being unloaded,
6800147868eSNuno Antunes 		 * so stop being persistant.
6810147868eSNuno Antunes 		 * Actually undo all the things we did on creation.
6820147868eSNuno Antunes 		 * Assume the ifp has already been freed.
6830147868eSNuno Antunes 		 */
6840147868eSNuno Antunes 		NG_NODE_SET_PRIVATE(node, NULL);
6850147868eSNuno Antunes 		kfree(priv, M_NETGRAPH);
6860147868eSNuno Antunes 		NG_NODE_UNREF(node);	/* free node itself */
6870147868eSNuno Antunes 		return (0);
6880147868eSNuno Antunes 	}
6890147868eSNuno Antunes 	if (priv->promisc) {		/* disable promiscuous mode */
6900147868eSNuno Antunes 		(void)ifpromisc(priv->ifp, 0);
6910147868eSNuno Antunes 		priv->promisc = 0;
6920147868eSNuno Antunes 	}
6930147868eSNuno Antunes 	priv->autoSrcAddr = 1;		/* reset auto-src-addr flag */
6940147868eSNuno Antunes 	NG_NODE_REVIVE(node);		/* Signal ng_rmnode we are persisant */
6950147868eSNuno Antunes 
6960147868eSNuno Antunes 	return (0);
6970147868eSNuno Antunes }
6980147868eSNuno Antunes 
6990147868eSNuno Antunes /*
7000147868eSNuno Antunes  * Hook disconnection.
7010147868eSNuno Antunes  */
7020147868eSNuno Antunes static int
ng_ether_disconnect(hook_p hook)7030147868eSNuno Antunes ng_ether_disconnect(hook_p hook)
7040147868eSNuno Antunes {
7050147868eSNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
7060147868eSNuno Antunes 
7070147868eSNuno Antunes 	if (hook == priv->upper) {
7080147868eSNuno Antunes 		priv->upper = NULL;
7090147868eSNuno Antunes 		if (priv->ifp != NULL)		/* restore h/w csum */
7100147868eSNuno Antunes 			priv->ifp->if_hwassist = priv->hwassist;
7110147868eSNuno Antunes 	} else if (hook == priv->lower)
7120147868eSNuno Antunes 		priv->lower = NULL;
7130147868eSNuno Antunes 	else if (hook == priv->orphan)
7140147868eSNuno Antunes 		priv->orphan = NULL;
7150147868eSNuno Antunes 	else
7160147868eSNuno Antunes 		panic("%s: weird hook", __func__);
7170147868eSNuno Antunes 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
7180147868eSNuno Antunes 	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
7190147868eSNuno Antunes 		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
7200147868eSNuno Antunes 	return (0);
7210147868eSNuno Antunes }
7220147868eSNuno Antunes 
7230147868eSNuno Antunes /******************************************************************
7240147868eSNuno Antunes 		    	INITIALIZATION
7250147868eSNuno Antunes ******************************************************************/
7260147868eSNuno Antunes 
7270147868eSNuno Antunes /*
7280147868eSNuno Antunes  * Handle loading and unloading for this node type.
7290147868eSNuno Antunes  */
7300147868eSNuno Antunes static int
ng_ether_mod_event(module_t mod,int event,void * data)7310147868eSNuno Antunes ng_ether_mod_event(module_t mod, int event, void *data)
7320147868eSNuno Antunes {
7330147868eSNuno Antunes 	struct ifnet *ifp;
7340147868eSNuno Antunes 	int error = 0;
7350147868eSNuno Antunes 
7360147868eSNuno Antunes 	crit_enter();
7370147868eSNuno Antunes 	switch (event) {
7380147868eSNuno Antunes 	case MOD_LOAD:
7390147868eSNuno Antunes 
7400147868eSNuno Antunes 		/* Register function hooks */
7410147868eSNuno Antunes 		if (ng_ether_attach_p != NULL) {
7420147868eSNuno Antunes 			error = EEXIST;
7430147868eSNuno Antunes 			break;
7440147868eSNuno Antunes 		}
7450147868eSNuno Antunes 		ng_ether_attach_p = ng_ether_attach;
7460147868eSNuno Antunes 		ng_ether_detach_p = ng_ether_detach;
7470147868eSNuno Antunes 		ng_ether_output_p = ng_ether_output;
7480147868eSNuno Antunes 		ng_ether_input_p = ng_ether_input;
7490147868eSNuno Antunes 		ng_ether_input_orphan_p = ng_ether_input_orphan;
7500147868eSNuno Antunes #if 0
7510147868eSNuno Antunes 		ng_ether_link_state_p = ng_ether_link_state;
7520147868eSNuno Antunes #endif
7530147868eSNuno Antunes 
7540147868eSNuno Antunes 		/* Create nodes for any already-existing Ethernet interfaces */
755*55d4a94aSSepherosa Ziehau 		ifnet_lock();
756*55d4a94aSSepherosa Ziehau 		TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
7570147868eSNuno Antunes 			if (ifp->if_type == IFT_ETHER
7580147868eSNuno Antunes 			    || ifp->if_type == IFT_L2VLAN)
7590147868eSNuno Antunes 				ng_ether_attach(ifp);
7600147868eSNuno Antunes 		}
761*55d4a94aSSepherosa Ziehau 		ifnet_unlock();
7620147868eSNuno Antunes 		break;
7630147868eSNuno Antunes 
7640147868eSNuno Antunes 	case MOD_UNLOAD:
7650147868eSNuno Antunes 
7660147868eSNuno Antunes 		/*
7670147868eSNuno Antunes 		 * Note that the base code won't try to unload us until
7680147868eSNuno Antunes 		 * all nodes have been removed, and that can't happen
7690147868eSNuno Antunes 		 * until all Ethernet interfaces are removed. In any
7700147868eSNuno Antunes 		 * case, we know there are no nodes left if the action
7710147868eSNuno Antunes 		 * is MOD_UNLOAD, so there's no need to detach any nodes.
7720147868eSNuno Antunes 		 */
7730147868eSNuno Antunes 
7740147868eSNuno Antunes 		/* Unregister function hooks */
7750147868eSNuno Antunes 		ng_ether_attach_p = NULL;
7760147868eSNuno Antunes 		ng_ether_detach_p = NULL;
7770147868eSNuno Antunes 		ng_ether_output_p = NULL;
7780147868eSNuno Antunes 		ng_ether_input_p = NULL;
7790147868eSNuno Antunes 		ng_ether_input_orphan_p = NULL;
7800147868eSNuno Antunes #if 0
7810147868eSNuno Antunes 		ng_ether_link_state_p = NULL;
7820147868eSNuno Antunes #endif
7830147868eSNuno Antunes 		break;
7840147868eSNuno Antunes 
7850147868eSNuno Antunes 	default:
7860147868eSNuno Antunes 		error = EOPNOTSUPP;
7870147868eSNuno Antunes 		break;
7880147868eSNuno Antunes 	}
7890147868eSNuno Antunes 	crit_exit();
7900147868eSNuno Antunes 	return (error);
7910147868eSNuno Antunes }
7920147868eSNuno Antunes 
793