xref: /freebsd/sys/netgraph/ng_gif.c (revision fc74a9f93a5fbc83262aa12084404ac953c854b5)
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 
92fc74a9f9SBrooks Davis #define IFP2NG(ifp)  ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph)
93fc74a9f9SBrooks Davis #define IFP2NG_SET(ifp, val)  (((struct gif_softc *)(ifp->if_softc))->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_DEPEND(ng_gif, if_gif, 1,1,1);
15794408d94SBrooks Davis NETGRAPH_INIT(gif, &ng_gif_typestruct);
15894408d94SBrooks Davis 
15994408d94SBrooks Davis /******************************************************************
16094408d94SBrooks Davis 		       GIF FUNCTION HOOKS
16194408d94SBrooks Davis ******************************************************************/
16294408d94SBrooks Davis 
16394408d94SBrooks Davis /*
16494408d94SBrooks Davis  * Handle a packet that has come in on an interface. We get to
16594408d94SBrooks Davis  * look at it here before any upper layer protocols do.
16694408d94SBrooks Davis  *
16794408d94SBrooks Davis  * NOTE: this function will get called at splimp()
16894408d94SBrooks Davis  */
16994408d94SBrooks Davis static void
17094408d94SBrooks Davis ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)
17194408d94SBrooks Davis {
17294408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
17394408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
17494408d94SBrooks Davis 
17594408d94SBrooks Davis 	/* If "lower" hook not connected, let packet continue */
17694408d94SBrooks Davis 	if (priv->lower == NULL || priv->lowerOrphan)
17794408d94SBrooks Davis 		return;
17894408d94SBrooks Davis 	ng_gif_input2(node, mp, af);
17994408d94SBrooks Davis }
18094408d94SBrooks Davis 
18194408d94SBrooks Davis /*
18294408d94SBrooks Davis  * Handle a packet that has come in on an interface, and which
18394408d94SBrooks Davis  * does not match any of our known protocols (an ``orphan'').
18494408d94SBrooks Davis  *
18594408d94SBrooks Davis  * NOTE: this function will get called at splimp()
18694408d94SBrooks Davis  */
18794408d94SBrooks Davis static void
18894408d94SBrooks Davis ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
18994408d94SBrooks Davis {
19094408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
19194408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
19294408d94SBrooks Davis 
19394408d94SBrooks Davis 	/* If "orphan" hook not connected, let packet continue */
19494408d94SBrooks Davis 	if (priv->lower == NULL || !priv->lowerOrphan) {
19594408d94SBrooks Davis 		m_freem(m);
19694408d94SBrooks Davis 		return;
19794408d94SBrooks Davis 	}
19894408d94SBrooks Davis 	ng_gif_input2(node, &m, af);
19994408d94SBrooks Davis 	if (m != NULL)
20094408d94SBrooks Davis 		m_freem(m);
20194408d94SBrooks Davis }
20294408d94SBrooks Davis 
20394408d94SBrooks Davis /*
20494408d94SBrooks Davis  * Handle a packet that has come in on a gif interface.
20594408d94SBrooks Davis  * Attach the address family to the mbuf for later use.
20694408d94SBrooks Davis  *
20794408d94SBrooks Davis  * NOTE: this function will get called at splimp()
20894408d94SBrooks Davis  */
20994408d94SBrooks Davis static void
21094408d94SBrooks Davis ng_gif_input2(node_p node, struct mbuf **mp, int af)
21194408d94SBrooks Davis {
21294408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
21394408d94SBrooks Davis 	int error;
21494408d94SBrooks Davis 
21594408d94SBrooks Davis 	/* Glue address family on */
21694408d94SBrooks Davis 	if ((error = ng_gif_glue_af(mp, af)) != 0)
21794408d94SBrooks Davis 		return;
21894408d94SBrooks Davis 
21994408d94SBrooks Davis 	/* Send out lower/orphan hook */
22094408d94SBrooks Davis 	NG_SEND_DATA_ONLY(error, priv->lower, *mp);
22194408d94SBrooks Davis 	*mp = NULL;
22294408d94SBrooks Davis }
22394408d94SBrooks Davis 
22494408d94SBrooks Davis /*
22594408d94SBrooks Davis  * A new gif interface has been attached.
22694408d94SBrooks Davis  * Create a new node for it, etc.
22794408d94SBrooks Davis  */
22894408d94SBrooks Davis static void
22994408d94SBrooks Davis ng_gif_attach(struct ifnet *ifp)
23094408d94SBrooks Davis {
23194408d94SBrooks Davis 	priv_p priv;
23294408d94SBrooks Davis 	node_p node;
23394408d94SBrooks Davis 
23494408d94SBrooks Davis 	/* Create node */
2356e551fb6SDavid E. O'Brien 	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
23694408d94SBrooks Davis 	if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
23794408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2389bf40edeSBrooks Davis 		    __func__, "create node", ifp->if_xname);
23994408d94SBrooks Davis 		return;
24094408d94SBrooks Davis 	}
24194408d94SBrooks Davis 
24294408d94SBrooks Davis 	/* Allocate private data */
24394408d94SBrooks Davis 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
24494408d94SBrooks Davis 	if (priv == NULL) {
24594408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2469bf40edeSBrooks Davis 		    __func__, "allocate memory", ifp->if_xname);
24794408d94SBrooks Davis 		NG_NODE_UNREF(node);
24894408d94SBrooks Davis 		return;
24994408d94SBrooks Davis 	}
25094408d94SBrooks Davis 	NG_NODE_SET_PRIVATE(node, priv);
25194408d94SBrooks Davis 	priv->ifp = ifp;
252445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, node);
25394408d94SBrooks Davis 
25494408d94SBrooks Davis 	/* Try to give the node the same name as the interface */
2559bf40edeSBrooks Davis 	if (ng_name_node(node, ifp->if_xname) != 0) {
25694408d94SBrooks Davis 		log(LOG_WARNING, "%s: can't name node %s\n",
2579bf40edeSBrooks Davis 		    __func__, ifp->if_xname);
25894408d94SBrooks Davis 	}
25994408d94SBrooks Davis }
26094408d94SBrooks Davis 
26194408d94SBrooks Davis /*
2627360079aSBrooks Davis  * An interface is being detached.
26394408d94SBrooks Davis  * REALLY Destroy its node.
26494408d94SBrooks Davis  */
26594408d94SBrooks Davis static void
26694408d94SBrooks Davis ng_gif_detach(struct ifnet *ifp)
26794408d94SBrooks Davis {
26894408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
269917a7daaSPoul-Henning Kamp 	priv_p priv;
27094408d94SBrooks Davis 
27194408d94SBrooks Davis 	if (node == NULL)		/* no node (why not?), ignore */
27294408d94SBrooks Davis 		return;
2733f54070bSColin Percival 	priv = NG_NODE_PRIVATE(node);
27494408d94SBrooks Davis 	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
27594408d94SBrooks Davis 	/*
27694408d94SBrooks Davis 	 * We can't assume the ifnet is still around when we run shutdown
27794408d94SBrooks Davis 	 * So zap it now. XXX We HOPE that anything running at this time
27894408d94SBrooks Davis 	 * handles it (as it should in the non netgraph case).
27994408d94SBrooks Davis 	 */
280445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, NULL);
28194408d94SBrooks Davis 	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
28294408d94SBrooks Davis 	ng_rmnode_self(node);		/* remove all netgraph parts */
28394408d94SBrooks Davis }
28494408d94SBrooks Davis 
28594408d94SBrooks Davis /*
2867360079aSBrooks Davis  * Optimization for gluing the address family onto
28794408d94SBrooks Davis  * the front of an incoming packet.
28894408d94SBrooks Davis  */
28994408d94SBrooks Davis static int
29094408d94SBrooks Davis ng_gif_glue_af(struct mbuf **mp, int af)
29194408d94SBrooks Davis {
29294408d94SBrooks Davis 	struct mbuf *m = *mp;
29394408d94SBrooks Davis 	int error = 0;
29494408d94SBrooks Davis 	sa_family_t tmp_af;
29594408d94SBrooks Davis 
29694408d94SBrooks Davis 	tmp_af = (sa_family_t) af;
29794408d94SBrooks Davis 
29894408d94SBrooks Davis 	/*
29994408d94SBrooks Davis 	 * XXX: should try to bring back some of the optimizations from
30094408d94SBrooks Davis 	 * ng_ether.c
30194408d94SBrooks Davis 	 */
30294408d94SBrooks Davis 
30394408d94SBrooks Davis 	/*
30494408d94SBrooks Davis 	 * Doing anything more is likely to get more
30594408d94SBrooks Davis 	 * expensive than it's worth..
30694408d94SBrooks Davis 	 * it's probable that everything else is in one
30794408d94SBrooks Davis 	 * big lump. The next node will do an m_pullup()
30894408d94SBrooks Davis 	 * for exactly the amount of data it needs and
30994408d94SBrooks Davis 	 * hopefully everything after that will not
31094408d94SBrooks Davis 	 * need one. So let's just use M_PREPEND.
31194408d94SBrooks Davis 	 */
312a163d034SWarner Losh 	M_PREPEND(m, sizeof (tmp_af), M_DONTWAIT);
31394408d94SBrooks Davis 	if (m == NULL) {
31494408d94SBrooks Davis 		error = ENOBUFS;
31594408d94SBrooks Davis 		goto done;
31694408d94SBrooks Davis 	}
31794408d94SBrooks Davis 
31894408d94SBrooks Davis #if 0
31994408d94SBrooks Davis copy:
32094408d94SBrooks Davis #endif
32194408d94SBrooks Davis 	/* Copy header and return (possibly new) mbuf */
32294408d94SBrooks Davis 	*mtod(m, sa_family_t *) = tmp_af;
32394408d94SBrooks Davis #if 0
32494408d94SBrooks Davis 	bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
32594408d94SBrooks Davis #endif
32694408d94SBrooks Davis done:
32794408d94SBrooks Davis 	*mp = m;
32894408d94SBrooks Davis 	return error;
32994408d94SBrooks Davis }
33094408d94SBrooks Davis 
33194408d94SBrooks Davis /******************************************************************
33294408d94SBrooks Davis 		    NETGRAPH NODE METHODS
33394408d94SBrooks Davis ******************************************************************/
33494408d94SBrooks Davis 
33594408d94SBrooks Davis /*
33694408d94SBrooks Davis  * It is not possible or allowable to create a node of this type.
33794408d94SBrooks Davis  * Nodes get created when the interface is attached (or, when
33894408d94SBrooks Davis  * this node type's KLD is loaded).
33994408d94SBrooks Davis  */
34094408d94SBrooks Davis static int
34194408d94SBrooks Davis ng_gif_constructor(node_p node)
34294408d94SBrooks Davis {
34394408d94SBrooks Davis 	return (EINVAL);
34494408d94SBrooks Davis }
34594408d94SBrooks Davis 
34694408d94SBrooks Davis /*
34794408d94SBrooks Davis  * Check for attaching a new hook.
34894408d94SBrooks Davis  */
34994408d94SBrooks Davis static	int
35094408d94SBrooks Davis ng_gif_newhook(node_p node, hook_p hook, const char *name)
35194408d94SBrooks Davis {
35294408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
35394408d94SBrooks Davis 	u_char orphan = priv->lowerOrphan;
35494408d94SBrooks Davis 	hook_p *hookptr;
35594408d94SBrooks Davis 
35694408d94SBrooks Davis 	/* Divert hook is an alias for lower */
35794408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
35894408d94SBrooks Davis 		name = NG_GIF_HOOK_LOWER;
35994408d94SBrooks Davis 
36094408d94SBrooks Davis 	/* Which hook? */
36194408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
36294408d94SBrooks Davis 		hookptr = &priv->lower;
36394408d94SBrooks Davis 		orphan = 0;
36494408d94SBrooks Davis 	} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
36594408d94SBrooks Davis 		hookptr = &priv->lower;
36694408d94SBrooks Davis 		orphan = 1;
36794408d94SBrooks Davis 	} else
36894408d94SBrooks Davis 		return (EINVAL);
36994408d94SBrooks Davis 
37094408d94SBrooks Davis 	/* Check if already connected (shouldn't be, but doesn't hurt) */
37194408d94SBrooks Davis 	if (*hookptr != NULL)
37294408d94SBrooks Davis 		return (EISCONN);
37394408d94SBrooks Davis 
37494408d94SBrooks Davis 	/* OK */
37594408d94SBrooks Davis 	*hookptr = hook;
37694408d94SBrooks Davis 	priv->lowerOrphan = orphan;
37794408d94SBrooks Davis 	return (0);
37894408d94SBrooks Davis }
37994408d94SBrooks Davis 
38094408d94SBrooks Davis /*
38194408d94SBrooks Davis  * Hooks are attached, adjust to force queueing.
38294408d94SBrooks Davis  * We don't really care which hook it is.
38394408d94SBrooks Davis  * they should all be queuing for outgoing data.
38494408d94SBrooks Davis  */
38594408d94SBrooks Davis static	int
38694408d94SBrooks Davis ng_gif_connect(hook_p hook)
38794408d94SBrooks Davis {
38894408d94SBrooks Davis 	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
38994408d94SBrooks Davis 	return (0);
39094408d94SBrooks Davis }
39194408d94SBrooks Davis 
39294408d94SBrooks Davis /*
39394408d94SBrooks Davis  * Receive an incoming control message.
39494408d94SBrooks Davis  */
39594408d94SBrooks Davis static int
39694408d94SBrooks Davis ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
39794408d94SBrooks Davis {
39894408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
39994408d94SBrooks Davis 	struct ng_mesg *resp = NULL;
40094408d94SBrooks Davis 	int error = 0;
40194408d94SBrooks Davis 	struct ng_mesg *msg;
40294408d94SBrooks Davis 
40394408d94SBrooks Davis 	NGI_GET_MSG(item, msg);
40494408d94SBrooks Davis 	switch (msg->header.typecookie) {
40594408d94SBrooks Davis 	case NGM_GIF_COOKIE:
40694408d94SBrooks Davis 		switch (msg->header.cmd) {
40794408d94SBrooks Davis 		case NGM_GIF_GET_IFNAME:
408bbb75d78SRuslan Ermilov 			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
40994408d94SBrooks Davis 			if (resp == NULL) {
41094408d94SBrooks Davis 				error = ENOMEM;
41194408d94SBrooks Davis 				break;
41294408d94SBrooks Davis 			}
413bbb75d78SRuslan Ermilov 			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
41494408d94SBrooks Davis 			break;
41594408d94SBrooks Davis 		case NGM_GIF_GET_IFINDEX:
41694408d94SBrooks Davis 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
41794408d94SBrooks Davis 			if (resp == NULL) {
41894408d94SBrooks Davis 				error = ENOMEM;
41994408d94SBrooks Davis 				break;
42094408d94SBrooks Davis 			}
42194408d94SBrooks Davis 			*((u_int32_t *)resp->data) = priv->ifp->if_index;
42294408d94SBrooks Davis 			break;
42394408d94SBrooks Davis 		default:
42494408d94SBrooks Davis 			error = EINVAL;
42594408d94SBrooks Davis 			break;
42694408d94SBrooks Davis 		}
42794408d94SBrooks Davis 		break;
42894408d94SBrooks Davis 	default:
42994408d94SBrooks Davis 		error = EINVAL;
43094408d94SBrooks Davis 		break;
43194408d94SBrooks Davis 	}
43294408d94SBrooks Davis 	NG_RESPOND_MSG(error, node, item, resp);
43394408d94SBrooks Davis 	NG_FREE_MSG(msg);
43494408d94SBrooks Davis 	return (error);
43594408d94SBrooks Davis }
43694408d94SBrooks Davis 
43794408d94SBrooks Davis /*
43894408d94SBrooks Davis  * Receive data on a hook.
43994408d94SBrooks Davis  */
44094408d94SBrooks Davis static int
44194408d94SBrooks Davis ng_gif_rcvdata(hook_p hook, item_p item)
44294408d94SBrooks Davis {
44394408d94SBrooks Davis 	const node_p node = NG_HOOK_NODE(hook);
44494408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
44594408d94SBrooks Davis 	struct mbuf *m;
44694408d94SBrooks Davis 
44794408d94SBrooks Davis 	NGI_GET_M(item, m);
44894408d94SBrooks Davis 	NG_FREE_ITEM(item);
4493ca24c28SJulian Elischer 
45094408d94SBrooks Davis 	if (hook == priv->lower)
4513ca24c28SJulian Elischer 		return ng_gif_rcv_lower(node, m);
4526e551fb6SDavid E. O'Brien 	panic("%s: weird hook", __func__);
45394408d94SBrooks Davis }
45494408d94SBrooks Davis 
45594408d94SBrooks Davis /*
45694408d94SBrooks Davis  * Handle an mbuf received on the "lower" hook.
45794408d94SBrooks Davis  */
45894408d94SBrooks Davis static int
4593ca24c28SJulian Elischer ng_gif_rcv_lower(node_p node, struct mbuf *m)
46094408d94SBrooks Davis {
46194408d94SBrooks Davis 	struct sockaddr	dst;
46294408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
46394408d94SBrooks Davis 
46494408d94SBrooks Davis 	bzero(&dst, sizeof(dst));
46594408d94SBrooks Davis 
46694408d94SBrooks Davis 	/* Make sure header is fully pulled up */
46794408d94SBrooks Davis 	if (m->m_pkthdr.len < sizeof(sa_family_t)) {
46894408d94SBrooks Davis 		NG_FREE_M(m);
46994408d94SBrooks Davis 		return (EINVAL);
47094408d94SBrooks Davis 	}
47194408d94SBrooks Davis 	if (m->m_len < sizeof(sa_family_t)
47294408d94SBrooks Davis 	    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
47394408d94SBrooks Davis 		return (ENOBUFS);
47494408d94SBrooks Davis 	}
47594408d94SBrooks Davis 
47694408d94SBrooks Davis 	dst.sa_family = *mtod(m, sa_family_t *);
47794408d94SBrooks Davis 	m_adj(m, sizeof(sa_family_t));
47894408d94SBrooks Davis 
47994408d94SBrooks Davis 	/* Send it on its way */
48094408d94SBrooks Davis 	/*
48194408d94SBrooks Davis 	 * XXX: gif_output only uses dst for the family and passes the
48294408d94SBrooks Davis 	 * fourth argument (rt) to in{,6}_gif_output which ignore it.
48394408d94SBrooks Davis 	 * If this changes ng_gif will probably break.
48494408d94SBrooks Davis 	 */
48594408d94SBrooks Davis 	return gif_output(priv->ifp, m, &dst, NULL);
48694408d94SBrooks Davis }
48794408d94SBrooks Davis 
48894408d94SBrooks Davis /*
48994408d94SBrooks Davis  * Shutdown node. This resets the node but does not remove it
49094408d94SBrooks Davis  * unless the REALLY_DIE flag is set.
49194408d94SBrooks Davis  */
49294408d94SBrooks Davis static int
49394408d94SBrooks Davis ng_gif_shutdown(node_p node)
49494408d94SBrooks Davis {
49594408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
49694408d94SBrooks Davis 
497be4252b3SJulian Elischer 	if (node->nd_flags & NGF_REALLY_DIE) {
49894408d94SBrooks Davis 		/*
49994408d94SBrooks Davis 		 * WE came here because the gif interface is being destroyed,
50094408d94SBrooks Davis 		 * so stop being persistant.
50194408d94SBrooks Davis 		 * Actually undo all the things we did on creation.
50294408d94SBrooks Davis 		 * Assume the ifp has already been freed.
50394408d94SBrooks Davis 		 */
50494408d94SBrooks Davis 		NG_NODE_SET_PRIVATE(node, NULL);
50594408d94SBrooks Davis 		FREE(priv, M_NETGRAPH);
50694408d94SBrooks Davis 		NG_NODE_UNREF(node);	/* free node itself */
50794408d94SBrooks Davis 		return (0);
50894408d94SBrooks Davis 	}
509be4252b3SJulian Elischer 	NG_NODE_REVIVE(node);		/* Signal ng_rmnode we are persisant */
51094408d94SBrooks Davis 	return (0);
51194408d94SBrooks Davis }
51294408d94SBrooks Davis 
51394408d94SBrooks Davis /*
51494408d94SBrooks Davis  * Hook disconnection.
51594408d94SBrooks Davis  */
51694408d94SBrooks Davis static int
51794408d94SBrooks Davis ng_gif_disconnect(hook_p hook)
51894408d94SBrooks Davis {
51994408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
52094408d94SBrooks Davis 
52194408d94SBrooks Davis 	if (hook == priv->lower) {
52294408d94SBrooks Davis 		priv->lower = NULL;
52394408d94SBrooks Davis 		priv->lowerOrphan = 0;
52494408d94SBrooks Davis 	} else
5256e551fb6SDavid E. O'Brien 		panic("%s: weird hook", __func__);
52694408d94SBrooks Davis 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
52794408d94SBrooks Davis 	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
52894408d94SBrooks Davis 		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
52994408d94SBrooks Davis 
53094408d94SBrooks Davis 	return (0);
53194408d94SBrooks Davis }
53294408d94SBrooks Davis 
53394408d94SBrooks Davis /******************************************************************
53494408d94SBrooks Davis 		    	INITIALIZATION
53594408d94SBrooks Davis ******************************************************************/
53694408d94SBrooks Davis 
53794408d94SBrooks Davis /*
53894408d94SBrooks Davis  * Handle loading and unloading for this node type.
53994408d94SBrooks Davis  */
54094408d94SBrooks Davis static int
54194408d94SBrooks Davis ng_gif_mod_event(module_t mod, int event, void *data)
54294408d94SBrooks Davis {
54394408d94SBrooks Davis 	struct ifnet *ifp;
54494408d94SBrooks Davis 	int error = 0;
54594408d94SBrooks Davis 	int s;
54694408d94SBrooks Davis 
54794408d94SBrooks Davis 	s = splnet();
54894408d94SBrooks Davis 	switch (event) {
54994408d94SBrooks Davis 	case MOD_LOAD:
55094408d94SBrooks Davis 
55194408d94SBrooks Davis 		/* Register function hooks */
55294408d94SBrooks Davis 		if (ng_gif_attach_p != NULL) {
55394408d94SBrooks Davis 			error = EEXIST;
55494408d94SBrooks Davis 			break;
55594408d94SBrooks Davis 		}
55694408d94SBrooks Davis 		ng_gif_attach_p = ng_gif_attach;
55794408d94SBrooks Davis 		ng_gif_detach_p = ng_gif_detach;
55894408d94SBrooks Davis 		ng_gif_input_p = ng_gif_input;
55994408d94SBrooks Davis 		ng_gif_input_orphan_p = ng_gif_input_orphan;
56094408d94SBrooks Davis 
56194408d94SBrooks Davis 		/* Create nodes for any already-existing gif interfaces */
562b30a244cSJeffrey Hsu 		IFNET_RLOCK();
56394408d94SBrooks Davis 		TAILQ_FOREACH(ifp, &ifnet, if_link) {
56494408d94SBrooks Davis 			if (ifp->if_type == IFT_GIF)
56594408d94SBrooks Davis 				ng_gif_attach(ifp);
56694408d94SBrooks Davis 		}
567b30a244cSJeffrey Hsu 		IFNET_RUNLOCK();
56894408d94SBrooks Davis 		break;
56994408d94SBrooks Davis 
57094408d94SBrooks Davis 	case MOD_UNLOAD:
57194408d94SBrooks Davis 
57294408d94SBrooks Davis 		/*
57394408d94SBrooks Davis 		 * Note that the base code won't try to unload us until
57494408d94SBrooks Davis 		 * all nodes have been removed, and that can't happen
57594408d94SBrooks Davis 		 * until all gif interfaces are destroyed. In any
57694408d94SBrooks Davis 		 * case, we know there are no nodes left if the action
57794408d94SBrooks Davis 		 * is MOD_UNLOAD, so there's no need to detach any nodes.
57894408d94SBrooks Davis 		 *
57994408d94SBrooks Davis 		 * XXX: what about manual unloads?!?
58094408d94SBrooks Davis 		 */
58194408d94SBrooks Davis 
58294408d94SBrooks Davis 		/* Unregister function hooks */
58394408d94SBrooks Davis 		ng_gif_attach_p = NULL;
58494408d94SBrooks Davis 		ng_gif_detach_p = NULL;
58594408d94SBrooks Davis 		ng_gif_input_p = NULL;
58694408d94SBrooks Davis 		ng_gif_input_orphan_p = NULL;
58794408d94SBrooks Davis 		break;
58894408d94SBrooks Davis 
58994408d94SBrooks Davis 	default:
59094408d94SBrooks Davis 		error = EOPNOTSUPP;
59194408d94SBrooks Davis 		break;
59294408d94SBrooks Davis 	}
59394408d94SBrooks Davis 	splx(s);
59494408d94SBrooks Davis 	return (error);
59594408d94SBrooks Davis }
59694408d94SBrooks Davis 
597