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