xref: /freebsd/sys/netgraph/ng_gif.c (revision c398230b64aea809cb7c5cea8db580af7097920c)
194408d94SBrooks Davis /*
294408d94SBrooks Davis  * ng_gif.c
3c398230bSWarner Losh  */
4c398230bSWarner Losh 
5c398230bSWarner Losh /*-
694408d94SBrooks Davis  * Copyright 2001 The Aerospace Corporation.  All rights reserved.
794408d94SBrooks Davis  *
894408d94SBrooks Davis  * Redistribution and use in source and binary forms, with or without
994408d94SBrooks Davis  * modification, are permitted provided that the following conditions
1094408d94SBrooks Davis  * are met:
11cf776d81SBrooks Davis  *
1294408d94SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
13cf776d81SBrooks Davis  *    notice, this list of conditions, and the following disclaimer.
1494408d94SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
15cf776d81SBrooks Davis  *    notice, this list of conditions, and the following disclaimer in the
1694408d94SBrooks Davis  *    documentation and/or other materials provided with the distribution.
17cf776d81SBrooks Davis  * 3. The name of The Aerospace Corporation may not be used to endorse or
18cf776d81SBrooks Davis  *    promote products derived from this software.
1994408d94SBrooks Davis  *
2094408d94SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
2194408d94SBrooks Davis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2294408d94SBrooks Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2394408d94SBrooks Davis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
2494408d94SBrooks Davis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2594408d94SBrooks Davis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2694408d94SBrooks Davis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2794408d94SBrooks Davis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2894408d94SBrooks Davis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2994408d94SBrooks Davis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3094408d94SBrooks Davis  * SUCH DAMAGE.
3194408d94SBrooks Davis  *
3294408d94SBrooks Davis  *
3394408d94SBrooks Davis  * Copyright (c) 1996-2000 Whistle Communications, Inc.
3494408d94SBrooks Davis  * All rights reserved.
3594408d94SBrooks Davis  *
3694408d94SBrooks Davis  * Subject to the following obligations and disclaimer of warranty, use and
3794408d94SBrooks Davis  * redistribution of this software, in source or object code forms, with or
3894408d94SBrooks Davis  * without modifications are expressly permitted by Whistle Communications;
3994408d94SBrooks Davis  * provided, however, that:
4094408d94SBrooks Davis  * 1. Any and all reproductions of the source or object code must include the
4194408d94SBrooks Davis  *    copyright notice above and the following disclaimer of warranties; and
4294408d94SBrooks Davis  * 2. No rights are granted, in any manner or form, to use Whistle
4394408d94SBrooks Davis  *    Communications, Inc. trademarks, including the mark "WHISTLE
4494408d94SBrooks Davis  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
4594408d94SBrooks Davis  *    such appears in the above copyright notice or in the software.
4694408d94SBrooks Davis  *
4794408d94SBrooks Davis  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
4894408d94SBrooks Davis  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
4994408d94SBrooks Davis  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
5094408d94SBrooks Davis  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
5194408d94SBrooks Davis  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
5294408d94SBrooks Davis  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
5394408d94SBrooks Davis  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
5494408d94SBrooks Davis  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
5594408d94SBrooks Davis  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
5694408d94SBrooks Davis  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
5794408d94SBrooks Davis  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
5894408d94SBrooks Davis  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
5994408d94SBrooks Davis  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
6094408d94SBrooks Davis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6194408d94SBrooks Davis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
6294408d94SBrooks Davis  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
6394408d94SBrooks Davis  * OF SUCH DAMAGE.
6494408d94SBrooks Davis  *
6594408d94SBrooks Davis  * $FreeBSD$
6694408d94SBrooks Davis  */
6794408d94SBrooks Davis 
6894408d94SBrooks Davis /*
6994408d94SBrooks Davis  * ng_gif(4) netgraph node type
7094408d94SBrooks Davis  */
7194408d94SBrooks Davis 
7294408d94SBrooks Davis #include <sys/param.h>
7394408d94SBrooks Davis #include <sys/systm.h>
7494408d94SBrooks Davis #include <sys/kernel.h>
7594408d94SBrooks Davis #include <sys/malloc.h>
7694408d94SBrooks Davis #include <sys/mbuf.h>
7794408d94SBrooks Davis #include <sys/errno.h>
7894408d94SBrooks Davis #include <sys/syslog.h>
7994408d94SBrooks Davis #include <sys/socket.h>
8094408d94SBrooks Davis 
8194408d94SBrooks Davis #include <net/if.h>
8294408d94SBrooks Davis #include <net/route.h>
8394408d94SBrooks Davis #include <net/if_types.h>
8494408d94SBrooks Davis #include <net/if_var.h>
8594408d94SBrooks Davis #include <net/if_gif.h>
8694408d94SBrooks Davis 
8794408d94SBrooks Davis #include <netgraph/ng_message.h>
8894408d94SBrooks Davis #include <netgraph/netgraph.h>
8994408d94SBrooks Davis #include <netgraph/ng_parse.h>
9094408d94SBrooks Davis #include <netgraph/ng_gif.h>
9194408d94SBrooks Davis 
9294408d94SBrooks Davis #define IFP2NG(ifp)  ((struct ng_node *)((struct gif_softc *)(ifp))->gif_netgraph)
93445e045bSAlexander Kabaev #define IFP2NG_SET(ifp, val)  (((struct gif_softc *)(ifp))->gif_netgraph = (val))
9494408d94SBrooks Davis 
9594408d94SBrooks Davis /* Per-node private data */
9694408d94SBrooks Davis struct private {
9794408d94SBrooks Davis 	struct ifnet	*ifp;		/* associated interface */
9894408d94SBrooks Davis 	hook_p		lower;		/* lower OR orphan hook connection */
9994408d94SBrooks Davis 	u_char		lowerOrphan;	/* whether lower is lower or orphan */
10094408d94SBrooks Davis };
10194408d94SBrooks Davis typedef struct private *priv_p;
10294408d94SBrooks Davis 
10394408d94SBrooks Davis /* Functional hooks called from if_gif.c */
10494408d94SBrooks Davis static void	ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);
10594408d94SBrooks Davis static void	ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);
10694408d94SBrooks Davis static void	ng_gif_attach(struct ifnet *ifp);
10794408d94SBrooks Davis static void	ng_gif_detach(struct ifnet *ifp);
10894408d94SBrooks Davis 
10994408d94SBrooks Davis /* Other functions */
11094408d94SBrooks Davis static void	ng_gif_input2(node_p node, struct mbuf **mp, int af);
11194408d94SBrooks Davis static int	ng_gif_glue_af(struct mbuf **mp, int af);
1123ca24c28SJulian Elischer static int	ng_gif_rcv_lower(node_p node, struct mbuf *m);
11394408d94SBrooks Davis 
11494408d94SBrooks Davis /* Netgraph node methods */
11594408d94SBrooks Davis static ng_constructor_t	ng_gif_constructor;
11694408d94SBrooks Davis static ng_rcvmsg_t	ng_gif_rcvmsg;
11794408d94SBrooks Davis static ng_shutdown_t	ng_gif_shutdown;
11894408d94SBrooks Davis static ng_newhook_t	ng_gif_newhook;
11994408d94SBrooks Davis static ng_connect_t	ng_gif_connect;
12094408d94SBrooks Davis static ng_rcvdata_t	ng_gif_rcvdata;
12194408d94SBrooks Davis static ng_disconnect_t	ng_gif_disconnect;
12294408d94SBrooks Davis static int		ng_gif_mod_event(module_t mod, int event, void *data);
12394408d94SBrooks Davis 
12494408d94SBrooks Davis /* List of commands and how to convert arguments to/from ASCII */
12594408d94SBrooks Davis static const struct ng_cmdlist ng_gif_cmdlist[] = {
12694408d94SBrooks Davis 	{
12794408d94SBrooks Davis 	  NGM_GIF_COOKIE,
12894408d94SBrooks Davis 	  NGM_GIF_GET_IFNAME,
12994408d94SBrooks Davis 	  "getifname",
13094408d94SBrooks Davis 	  NULL,
13194408d94SBrooks Davis 	  &ng_parse_string_type
13294408d94SBrooks Davis 	},
13394408d94SBrooks Davis 	{
13494408d94SBrooks Davis 	  NGM_GIF_COOKIE,
13594408d94SBrooks Davis 	  NGM_GIF_GET_IFINDEX,
13694408d94SBrooks Davis 	  "getifindex",
13794408d94SBrooks Davis 	  NULL,
13894408d94SBrooks Davis 	  &ng_parse_int32_type
13994408d94SBrooks Davis 	},
14094408d94SBrooks Davis 	{ 0 }
14194408d94SBrooks Davis };
14294408d94SBrooks Davis 
14394408d94SBrooks Davis static struct ng_type ng_gif_typestruct = {
144f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
145f8aae777SJulian Elischer 	.name =		NG_GIF_NODE_TYPE,
146f8aae777SJulian Elischer 	.mod_event =	ng_gif_mod_event,
147f8aae777SJulian Elischer 	.constructor =	ng_gif_constructor,
148f8aae777SJulian Elischer 	.rcvmsg =	ng_gif_rcvmsg,
149f8aae777SJulian Elischer 	.shutdown =	ng_gif_shutdown,
150f8aae777SJulian Elischer 	.newhook =	ng_gif_newhook,
151f8aae777SJulian Elischer 	.connect =	ng_gif_connect,
152f8aae777SJulian Elischer 	.rcvdata =	ng_gif_rcvdata,
153f8aae777SJulian Elischer 	.disconnect =	ng_gif_disconnect,
154f8aae777SJulian Elischer 	.cmdlist =	ng_gif_cmdlist,
15594408d94SBrooks Davis };
15694408d94SBrooks Davis MODULE_VERSION(ng_gif, 1);
15794408d94SBrooks Davis MODULE_DEPEND(ng_gif, if_gif, 1,1,1);
15894408d94SBrooks Davis NETGRAPH_INIT(gif, &ng_gif_typestruct);
15994408d94SBrooks Davis 
16094408d94SBrooks Davis /******************************************************************
16194408d94SBrooks Davis 		       GIF FUNCTION HOOKS
16294408d94SBrooks Davis ******************************************************************/
16394408d94SBrooks Davis 
16494408d94SBrooks Davis /*
16594408d94SBrooks Davis  * Handle a packet that has come in on an interface. We get to
16694408d94SBrooks Davis  * look at it here before any upper layer protocols do.
16794408d94SBrooks Davis  *
16894408d94SBrooks Davis  * NOTE: this function will get called at splimp()
16994408d94SBrooks Davis  */
17094408d94SBrooks Davis static void
17194408d94SBrooks Davis ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)
17294408d94SBrooks Davis {
17394408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
17494408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
17594408d94SBrooks Davis 
17694408d94SBrooks Davis 	/* If "lower" hook not connected, let packet continue */
17794408d94SBrooks Davis 	if (priv->lower == NULL || priv->lowerOrphan)
17894408d94SBrooks Davis 		return;
17994408d94SBrooks Davis 	ng_gif_input2(node, mp, af);
18094408d94SBrooks Davis }
18194408d94SBrooks Davis 
18294408d94SBrooks Davis /*
18394408d94SBrooks Davis  * Handle a packet that has come in on an interface, and which
18494408d94SBrooks Davis  * does not match any of our known protocols (an ``orphan'').
18594408d94SBrooks Davis  *
18694408d94SBrooks Davis  * NOTE: this function will get called at splimp()
18794408d94SBrooks Davis  */
18894408d94SBrooks Davis static void
18994408d94SBrooks Davis ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
19094408d94SBrooks Davis {
19194408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
19294408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
19394408d94SBrooks Davis 
19494408d94SBrooks Davis 	/* If "orphan" hook not connected, let packet continue */
19594408d94SBrooks Davis 	if (priv->lower == NULL || !priv->lowerOrphan) {
19694408d94SBrooks Davis 		m_freem(m);
19794408d94SBrooks Davis 		return;
19894408d94SBrooks Davis 	}
19994408d94SBrooks Davis 	ng_gif_input2(node, &m, af);
20094408d94SBrooks Davis 	if (m != NULL)
20194408d94SBrooks Davis 		m_freem(m);
20294408d94SBrooks Davis }
20394408d94SBrooks Davis 
20494408d94SBrooks Davis /*
20594408d94SBrooks Davis  * Handle a packet that has come in on a gif interface.
20694408d94SBrooks Davis  * Attach the address family to the mbuf for later use.
20794408d94SBrooks Davis  *
20894408d94SBrooks Davis  * NOTE: this function will get called at splimp()
20994408d94SBrooks Davis  */
21094408d94SBrooks Davis static void
21194408d94SBrooks Davis ng_gif_input2(node_p node, struct mbuf **mp, int af)
21294408d94SBrooks Davis {
21394408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
21494408d94SBrooks Davis 	int error;
21594408d94SBrooks Davis 
21694408d94SBrooks Davis 	/* Glue address family on */
21794408d94SBrooks Davis 	if ((error = ng_gif_glue_af(mp, af)) != 0)
21894408d94SBrooks Davis 		return;
21994408d94SBrooks Davis 
22094408d94SBrooks Davis 	/* Send out lower/orphan hook */
22194408d94SBrooks Davis 	NG_SEND_DATA_ONLY(error, priv->lower, *mp);
22294408d94SBrooks Davis 	*mp = NULL;
22394408d94SBrooks Davis }
22494408d94SBrooks Davis 
22594408d94SBrooks Davis /*
22694408d94SBrooks Davis  * A new gif interface has been attached.
22794408d94SBrooks Davis  * Create a new node for it, etc.
22894408d94SBrooks Davis  */
22994408d94SBrooks Davis static void
23094408d94SBrooks Davis ng_gif_attach(struct ifnet *ifp)
23194408d94SBrooks Davis {
23294408d94SBrooks Davis 	priv_p priv;
23394408d94SBrooks Davis 	node_p node;
23494408d94SBrooks Davis 
23594408d94SBrooks Davis 	/* Create node */
2366e551fb6SDavid E. O'Brien 	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
23794408d94SBrooks Davis 	if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
23894408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2399bf40edeSBrooks Davis 		    __func__, "create node", ifp->if_xname);
24094408d94SBrooks Davis 		return;
24194408d94SBrooks Davis 	}
24294408d94SBrooks Davis 
24394408d94SBrooks Davis 	/* Allocate private data */
24494408d94SBrooks Davis 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
24594408d94SBrooks Davis 	if (priv == NULL) {
24694408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2479bf40edeSBrooks Davis 		    __func__, "allocate memory", ifp->if_xname);
24894408d94SBrooks Davis 		NG_NODE_UNREF(node);
24994408d94SBrooks Davis 		return;
25094408d94SBrooks Davis 	}
25194408d94SBrooks Davis 	NG_NODE_SET_PRIVATE(node, priv);
25294408d94SBrooks Davis 	priv->ifp = ifp;
253445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, node);
25494408d94SBrooks Davis 
25594408d94SBrooks Davis 	/* Try to give the node the same name as the interface */
2569bf40edeSBrooks Davis 	if (ng_name_node(node, ifp->if_xname) != 0) {
25794408d94SBrooks Davis 		log(LOG_WARNING, "%s: can't name node %s\n",
2589bf40edeSBrooks Davis 		    __func__, ifp->if_xname);
25994408d94SBrooks Davis 	}
26094408d94SBrooks Davis }
26194408d94SBrooks Davis 
26294408d94SBrooks Davis /*
2637360079aSBrooks Davis  * An interface is being detached.
26494408d94SBrooks Davis  * REALLY Destroy its node.
26594408d94SBrooks Davis  */
26694408d94SBrooks Davis static void
26794408d94SBrooks Davis ng_gif_detach(struct ifnet *ifp)
26894408d94SBrooks Davis {
26994408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
270917a7daaSPoul-Henning Kamp 	priv_p priv;
27194408d94SBrooks Davis 
27294408d94SBrooks Davis 	if (node == NULL)		/* no node (why not?), ignore */
27394408d94SBrooks Davis 		return;
2743f54070bSColin Percival 	priv = NG_NODE_PRIVATE(node);
27594408d94SBrooks Davis 	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
27694408d94SBrooks Davis 	/*
27794408d94SBrooks Davis 	 * We can't assume the ifnet is still around when we run shutdown
27894408d94SBrooks Davis 	 * So zap it now. XXX We HOPE that anything running at this time
27994408d94SBrooks Davis 	 * handles it (as it should in the non netgraph case).
28094408d94SBrooks Davis 	 */
281445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, NULL);
28294408d94SBrooks Davis 	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
28394408d94SBrooks Davis 	ng_rmnode_self(node);		/* remove all netgraph parts */
28494408d94SBrooks Davis }
28594408d94SBrooks Davis 
28694408d94SBrooks Davis /*
2877360079aSBrooks Davis  * Optimization for gluing the address family onto
28894408d94SBrooks Davis  * the front of an incoming packet.
28994408d94SBrooks Davis  */
29094408d94SBrooks Davis static int
29194408d94SBrooks Davis ng_gif_glue_af(struct mbuf **mp, int af)
29294408d94SBrooks Davis {
29394408d94SBrooks Davis 	struct mbuf *m = *mp;
29494408d94SBrooks Davis 	int error = 0;
29594408d94SBrooks Davis 	sa_family_t tmp_af;
29694408d94SBrooks Davis 
29794408d94SBrooks Davis 	tmp_af = (sa_family_t) af;
29894408d94SBrooks Davis 
29994408d94SBrooks Davis 	/*
30094408d94SBrooks Davis 	 * XXX: should try to bring back some of the optimizations from
30194408d94SBrooks Davis 	 * ng_ether.c
30294408d94SBrooks Davis 	 */
30394408d94SBrooks Davis 
30494408d94SBrooks Davis 	/*
30594408d94SBrooks Davis 	 * Doing anything more is likely to get more
30694408d94SBrooks Davis 	 * expensive than it's worth..
30794408d94SBrooks Davis 	 * it's probable that everything else is in one
30894408d94SBrooks Davis 	 * big lump. The next node will do an m_pullup()
30994408d94SBrooks Davis 	 * for exactly the amount of data it needs and
31094408d94SBrooks Davis 	 * hopefully everything after that will not
31194408d94SBrooks Davis 	 * need one. So let's just use M_PREPEND.
31294408d94SBrooks Davis 	 */
313a163d034SWarner Losh 	M_PREPEND(m, sizeof (tmp_af), M_DONTWAIT);
31494408d94SBrooks Davis 	if (m == NULL) {
31594408d94SBrooks Davis 		error = ENOBUFS;
31694408d94SBrooks Davis 		goto done;
31794408d94SBrooks Davis 	}
31894408d94SBrooks Davis 
31994408d94SBrooks Davis #if 0
32094408d94SBrooks Davis copy:
32194408d94SBrooks Davis #endif
32294408d94SBrooks Davis 	/* Copy header and return (possibly new) mbuf */
32394408d94SBrooks Davis 	*mtod(m, sa_family_t *) = tmp_af;
32494408d94SBrooks Davis #if 0
32594408d94SBrooks Davis 	bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
32694408d94SBrooks Davis #endif
32794408d94SBrooks Davis done:
32894408d94SBrooks Davis 	*mp = m;
32994408d94SBrooks Davis 	return error;
33094408d94SBrooks Davis }
33194408d94SBrooks Davis 
33294408d94SBrooks Davis /******************************************************************
33394408d94SBrooks Davis 		    NETGRAPH NODE METHODS
33494408d94SBrooks Davis ******************************************************************/
33594408d94SBrooks Davis 
33694408d94SBrooks Davis /*
33794408d94SBrooks Davis  * It is not possible or allowable to create a node of this type.
33894408d94SBrooks Davis  * Nodes get created when the interface is attached (or, when
33994408d94SBrooks Davis  * this node type's KLD is loaded).
34094408d94SBrooks Davis  */
34194408d94SBrooks Davis static int
34294408d94SBrooks Davis ng_gif_constructor(node_p node)
34394408d94SBrooks Davis {
34494408d94SBrooks Davis 	return (EINVAL);
34594408d94SBrooks Davis }
34694408d94SBrooks Davis 
34794408d94SBrooks Davis /*
34894408d94SBrooks Davis  * Check for attaching a new hook.
34994408d94SBrooks Davis  */
35094408d94SBrooks Davis static	int
35194408d94SBrooks Davis ng_gif_newhook(node_p node, hook_p hook, const char *name)
35294408d94SBrooks Davis {
35394408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
35494408d94SBrooks Davis 	u_char orphan = priv->lowerOrphan;
35594408d94SBrooks Davis 	hook_p *hookptr;
35694408d94SBrooks Davis 
35794408d94SBrooks Davis 	/* Divert hook is an alias for lower */
35894408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
35994408d94SBrooks Davis 		name = NG_GIF_HOOK_LOWER;
36094408d94SBrooks Davis 
36194408d94SBrooks Davis 	/* Which hook? */
36294408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
36394408d94SBrooks Davis 		hookptr = &priv->lower;
36494408d94SBrooks Davis 		orphan = 0;
36594408d94SBrooks Davis 	} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
36694408d94SBrooks Davis 		hookptr = &priv->lower;
36794408d94SBrooks Davis 		orphan = 1;
36894408d94SBrooks Davis 	} else
36994408d94SBrooks Davis 		return (EINVAL);
37094408d94SBrooks Davis 
37194408d94SBrooks Davis 	/* Check if already connected (shouldn't be, but doesn't hurt) */
37294408d94SBrooks Davis 	if (*hookptr != NULL)
37394408d94SBrooks Davis 		return (EISCONN);
37494408d94SBrooks Davis 
37594408d94SBrooks Davis 	/* OK */
37694408d94SBrooks Davis 	*hookptr = hook;
37794408d94SBrooks Davis 	priv->lowerOrphan = orphan;
37894408d94SBrooks Davis 	return (0);
37994408d94SBrooks Davis }
38094408d94SBrooks Davis 
38194408d94SBrooks Davis /*
38294408d94SBrooks Davis  * Hooks are attached, adjust to force queueing.
38394408d94SBrooks Davis  * We don't really care which hook it is.
38494408d94SBrooks Davis  * they should all be queuing for outgoing data.
38594408d94SBrooks Davis  */
38694408d94SBrooks Davis static	int
38794408d94SBrooks Davis ng_gif_connect(hook_p hook)
38894408d94SBrooks Davis {
38994408d94SBrooks Davis 	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
39094408d94SBrooks Davis 	return (0);
39194408d94SBrooks Davis }
39294408d94SBrooks Davis 
39394408d94SBrooks Davis /*
39494408d94SBrooks Davis  * Receive an incoming control message.
39594408d94SBrooks Davis  */
39694408d94SBrooks Davis static int
39794408d94SBrooks Davis ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
39894408d94SBrooks Davis {
39994408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
40094408d94SBrooks Davis 	struct ng_mesg *resp = NULL;
40194408d94SBrooks Davis 	int error = 0;
40294408d94SBrooks Davis 	struct ng_mesg *msg;
40394408d94SBrooks Davis 
40494408d94SBrooks Davis 	NGI_GET_MSG(item, msg);
40594408d94SBrooks Davis 	switch (msg->header.typecookie) {
40694408d94SBrooks Davis 	case NGM_GIF_COOKIE:
40794408d94SBrooks Davis 		switch (msg->header.cmd) {
40894408d94SBrooks Davis 		case NGM_GIF_GET_IFNAME:
40994408d94SBrooks Davis 			NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
41094408d94SBrooks Davis 			if (resp == NULL) {
41194408d94SBrooks Davis 				error = ENOMEM;
41294408d94SBrooks Davis 				break;
41394408d94SBrooks Davis 			}
4149bf40edeSBrooks Davis 			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1);
41594408d94SBrooks Davis 			break;
41694408d94SBrooks Davis 		case NGM_GIF_GET_IFINDEX:
41794408d94SBrooks Davis 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
41894408d94SBrooks Davis 			if (resp == NULL) {
41994408d94SBrooks Davis 				error = ENOMEM;
42094408d94SBrooks Davis 				break;
42194408d94SBrooks Davis 			}
42294408d94SBrooks Davis 			*((u_int32_t *)resp->data) = priv->ifp->if_index;
42394408d94SBrooks Davis 			break;
42494408d94SBrooks Davis 		default:
42594408d94SBrooks Davis 			error = EINVAL;
42694408d94SBrooks Davis 			break;
42794408d94SBrooks Davis 		}
42894408d94SBrooks Davis 		break;
42994408d94SBrooks Davis 	default:
43094408d94SBrooks Davis 		error = EINVAL;
43194408d94SBrooks Davis 		break;
43294408d94SBrooks Davis 	}
43394408d94SBrooks Davis 	NG_RESPOND_MSG(error, node, item, resp);
43494408d94SBrooks Davis 	NG_FREE_MSG(msg);
43594408d94SBrooks Davis 	return (error);
43694408d94SBrooks Davis }
43794408d94SBrooks Davis 
43894408d94SBrooks Davis /*
43994408d94SBrooks Davis  * Receive data on a hook.
44094408d94SBrooks Davis  */
44194408d94SBrooks Davis static int
44294408d94SBrooks Davis ng_gif_rcvdata(hook_p hook, item_p item)
44394408d94SBrooks Davis {
44494408d94SBrooks Davis 	const node_p node = NG_HOOK_NODE(hook);
44594408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
44694408d94SBrooks Davis 	struct mbuf *m;
44794408d94SBrooks Davis 
44894408d94SBrooks Davis 	NGI_GET_M(item, m);
44994408d94SBrooks Davis 	NG_FREE_ITEM(item);
4503ca24c28SJulian Elischer 
45194408d94SBrooks Davis 	if (hook == priv->lower)
4523ca24c28SJulian Elischer 		return ng_gif_rcv_lower(node, m);
4536e551fb6SDavid E. O'Brien 	panic("%s: weird hook", __func__);
45494408d94SBrooks Davis }
45594408d94SBrooks Davis 
45694408d94SBrooks Davis /*
45794408d94SBrooks Davis  * Handle an mbuf received on the "lower" hook.
45894408d94SBrooks Davis  */
45994408d94SBrooks Davis static int
4603ca24c28SJulian Elischer ng_gif_rcv_lower(node_p node, struct mbuf *m)
46194408d94SBrooks Davis {
46294408d94SBrooks Davis 	struct sockaddr	dst;
46394408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
46494408d94SBrooks Davis 
46594408d94SBrooks Davis 	bzero(&dst, sizeof(dst));
46694408d94SBrooks Davis 
46794408d94SBrooks Davis 	/* Make sure header is fully pulled up */
46894408d94SBrooks Davis 	if (m->m_pkthdr.len < sizeof(sa_family_t)) {
46994408d94SBrooks Davis 		NG_FREE_M(m);
47094408d94SBrooks Davis 		return (EINVAL);
47194408d94SBrooks Davis 	}
47294408d94SBrooks Davis 	if (m->m_len < sizeof(sa_family_t)
47394408d94SBrooks Davis 	    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
47494408d94SBrooks Davis 		return (ENOBUFS);
47594408d94SBrooks Davis 	}
47694408d94SBrooks Davis 
47794408d94SBrooks Davis 	dst.sa_family = *mtod(m, sa_family_t *);
47894408d94SBrooks Davis 	m_adj(m, sizeof(sa_family_t));
47994408d94SBrooks Davis 
48094408d94SBrooks Davis 	/* Send it on its way */
48194408d94SBrooks Davis 	/*
48294408d94SBrooks Davis 	 * XXX: gif_output only uses dst for the family and passes the
48394408d94SBrooks Davis 	 * fourth argument (rt) to in{,6}_gif_output which ignore it.
48494408d94SBrooks Davis 	 * If this changes ng_gif will probably break.
48594408d94SBrooks Davis 	 */
48694408d94SBrooks Davis 	return gif_output(priv->ifp, m, &dst, NULL);
48794408d94SBrooks Davis }
48894408d94SBrooks Davis 
48994408d94SBrooks Davis /*
49094408d94SBrooks Davis  * Shutdown node. This resets the node but does not remove it
49194408d94SBrooks Davis  * unless the REALLY_DIE flag is set.
49294408d94SBrooks Davis  */
49394408d94SBrooks Davis static int
49494408d94SBrooks Davis ng_gif_shutdown(node_p node)
49594408d94SBrooks Davis {
49694408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
49794408d94SBrooks Davis 
498be4252b3SJulian Elischer 	if (node->nd_flags & NGF_REALLY_DIE) {
49994408d94SBrooks Davis 		/*
50094408d94SBrooks Davis 		 * WE came here because the gif interface is being destroyed,
50194408d94SBrooks Davis 		 * so stop being persistant.
50294408d94SBrooks Davis 		 * Actually undo all the things we did on creation.
50394408d94SBrooks Davis 		 * Assume the ifp has already been freed.
50494408d94SBrooks Davis 		 */
50594408d94SBrooks Davis 		NG_NODE_SET_PRIVATE(node, NULL);
50694408d94SBrooks Davis 		FREE(priv, M_NETGRAPH);
50794408d94SBrooks Davis 		NG_NODE_UNREF(node);	/* free node itself */
50894408d94SBrooks Davis 		return (0);
50994408d94SBrooks Davis 	}
510be4252b3SJulian Elischer 	NG_NODE_REVIVE(node);		/* Signal ng_rmnode we are persisant */
51194408d94SBrooks Davis 	return (0);
51294408d94SBrooks Davis }
51394408d94SBrooks Davis 
51494408d94SBrooks Davis /*
51594408d94SBrooks Davis  * Hook disconnection.
51694408d94SBrooks Davis  */
51794408d94SBrooks Davis static int
51894408d94SBrooks Davis ng_gif_disconnect(hook_p hook)
51994408d94SBrooks Davis {
52094408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
52194408d94SBrooks Davis 
52294408d94SBrooks Davis 	if (hook == priv->lower) {
52394408d94SBrooks Davis 		priv->lower = NULL;
52494408d94SBrooks Davis 		priv->lowerOrphan = 0;
52594408d94SBrooks Davis 	} else
5266e551fb6SDavid E. O'Brien 		panic("%s: weird hook", __func__);
52794408d94SBrooks Davis 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
52894408d94SBrooks Davis 	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
52994408d94SBrooks Davis 		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
53094408d94SBrooks Davis 
53194408d94SBrooks Davis 	return (0);
53294408d94SBrooks Davis }
53394408d94SBrooks Davis 
53494408d94SBrooks Davis /******************************************************************
53594408d94SBrooks Davis 		    	INITIALIZATION
53694408d94SBrooks Davis ******************************************************************/
53794408d94SBrooks Davis 
53894408d94SBrooks Davis /*
53994408d94SBrooks Davis  * Handle loading and unloading for this node type.
54094408d94SBrooks Davis  */
54194408d94SBrooks Davis static int
54294408d94SBrooks Davis ng_gif_mod_event(module_t mod, int event, void *data)
54394408d94SBrooks Davis {
54494408d94SBrooks Davis 	struct ifnet *ifp;
54594408d94SBrooks Davis 	int error = 0;
54694408d94SBrooks Davis 	int s;
54794408d94SBrooks Davis 
54894408d94SBrooks Davis 	s = splnet();
54994408d94SBrooks Davis 	switch (event) {
55094408d94SBrooks Davis 	case MOD_LOAD:
55194408d94SBrooks Davis 
55294408d94SBrooks Davis 		/* Register function hooks */
55394408d94SBrooks Davis 		if (ng_gif_attach_p != NULL) {
55494408d94SBrooks Davis 			error = EEXIST;
55594408d94SBrooks Davis 			break;
55694408d94SBrooks Davis 		}
55794408d94SBrooks Davis 		ng_gif_attach_p = ng_gif_attach;
55894408d94SBrooks Davis 		ng_gif_detach_p = ng_gif_detach;
55994408d94SBrooks Davis 		ng_gif_input_p = ng_gif_input;
56094408d94SBrooks Davis 		ng_gif_input_orphan_p = ng_gif_input_orphan;
56194408d94SBrooks Davis 
56294408d94SBrooks Davis 		/* Create nodes for any already-existing gif interfaces */
563b30a244cSJeffrey Hsu 		IFNET_RLOCK();
56494408d94SBrooks Davis 		TAILQ_FOREACH(ifp, &ifnet, if_link) {
56594408d94SBrooks Davis 			if (ifp->if_type == IFT_GIF)
56694408d94SBrooks Davis 				ng_gif_attach(ifp);
56794408d94SBrooks Davis 		}
568b30a244cSJeffrey Hsu 		IFNET_RUNLOCK();
56994408d94SBrooks Davis 		break;
57094408d94SBrooks Davis 
57194408d94SBrooks Davis 	case MOD_UNLOAD:
57294408d94SBrooks Davis 
57394408d94SBrooks Davis 		/*
57494408d94SBrooks Davis 		 * Note that the base code won't try to unload us until
57594408d94SBrooks Davis 		 * all nodes have been removed, and that can't happen
57694408d94SBrooks Davis 		 * until all gif interfaces are destroyed. In any
57794408d94SBrooks Davis 		 * case, we know there are no nodes left if the action
57894408d94SBrooks Davis 		 * is MOD_UNLOAD, so there's no need to detach any nodes.
57994408d94SBrooks Davis 		 *
58094408d94SBrooks Davis 		 * XXX: what about manual unloads?!?
58194408d94SBrooks Davis 		 */
58294408d94SBrooks Davis 
58394408d94SBrooks Davis 		/* Unregister function hooks */
58494408d94SBrooks Davis 		ng_gif_attach_p = NULL;
58594408d94SBrooks Davis 		ng_gif_detach_p = NULL;
58694408d94SBrooks Davis 		ng_gif_input_p = NULL;
58794408d94SBrooks Davis 		ng_gif_input_orphan_p = NULL;
58894408d94SBrooks Davis 		break;
58994408d94SBrooks Davis 
59094408d94SBrooks Davis 	default:
59194408d94SBrooks Davis 		error = EOPNOTSUPP;
59294408d94SBrooks Davis 		break;
59394408d94SBrooks Davis 	}
59494408d94SBrooks Davis 	splx(s);
59594408d94SBrooks Davis 	return (error);
59694408d94SBrooks Davis }
59794408d94SBrooks Davis 
598