xref: /freebsd/sys/netgraph/ng_gif.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
194408d94SBrooks Davis /*
294408d94SBrooks Davis  * ng_gif.c
3c398230bSWarner Losh  */
4c398230bSWarner Losh 
5c398230bSWarner Losh /*-
6fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause
7fe267a55SPedro F. Giffuni  *
894408d94SBrooks Davis  * Copyright 2001 The Aerospace Corporation.  All rights reserved.
994408d94SBrooks Davis  *
1094408d94SBrooks Davis  * Redistribution and use in source and binary forms, with or without
1194408d94SBrooks Davis  * modification, are permitted provided that the following conditions
1294408d94SBrooks Davis  * are met:
13cf776d81SBrooks Davis  *
1494408d94SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
15cf776d81SBrooks Davis  *    notice, this list of conditions, and the following disclaimer.
1694408d94SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
17cf776d81SBrooks Davis  *    notice, this list of conditions, and the following disclaimer in the
1894408d94SBrooks Davis  *    documentation and/or other materials provided with the distribution.
19cf776d81SBrooks Davis  * 3. The name of The Aerospace Corporation may not be used to endorse or
20cf776d81SBrooks Davis  *    promote products derived from this software.
2194408d94SBrooks Davis  *
2294408d94SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
2394408d94SBrooks Davis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2494408d94SBrooks Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2594408d94SBrooks Davis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
2694408d94SBrooks Davis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2794408d94SBrooks Davis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2894408d94SBrooks Davis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2994408d94SBrooks Davis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3094408d94SBrooks Davis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3194408d94SBrooks Davis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3294408d94SBrooks Davis  * SUCH DAMAGE.
3394408d94SBrooks Davis  *
3494408d94SBrooks Davis  *
3594408d94SBrooks Davis  * Copyright (c) 1996-2000 Whistle Communications, Inc.
3694408d94SBrooks Davis  * All rights reserved.
3794408d94SBrooks Davis  *
3894408d94SBrooks Davis  * Subject to the following obligations and disclaimer of warranty, use and
3994408d94SBrooks Davis  * redistribution of this software, in source or object code forms, with or
4094408d94SBrooks Davis  * without modifications are expressly permitted by Whistle Communications;
4194408d94SBrooks Davis  * provided, however, that:
4294408d94SBrooks Davis  * 1. Any and all reproductions of the source or object code must include the
4394408d94SBrooks Davis  *    copyright notice above and the following disclaimer of warranties; and
4494408d94SBrooks Davis  * 2. No rights are granted, in any manner or form, to use Whistle
4594408d94SBrooks Davis  *    Communications, Inc. trademarks, including the mark "WHISTLE
4694408d94SBrooks Davis  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
4794408d94SBrooks Davis  *    such appears in the above copyright notice or in the software.
4894408d94SBrooks Davis  *
4994408d94SBrooks Davis  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
5094408d94SBrooks Davis  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
5194408d94SBrooks Davis  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
5294408d94SBrooks Davis  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
5394408d94SBrooks Davis  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
5494408d94SBrooks Davis  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
5594408d94SBrooks Davis  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
5694408d94SBrooks Davis  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
5794408d94SBrooks Davis  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
5894408d94SBrooks Davis  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
5994408d94SBrooks Davis  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
6094408d94SBrooks Davis  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
6194408d94SBrooks Davis  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
6294408d94SBrooks Davis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6394408d94SBrooks Davis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
6494408d94SBrooks Davis  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
6594408d94SBrooks Davis  * OF SUCH DAMAGE.
6694408d94SBrooks Davis  */
6794408d94SBrooks Davis 
6894408d94SBrooks Davis /*
6994408d94SBrooks Davis  * ng_gif(4) netgraph node type
7094408d94SBrooks Davis  */
7194408d94SBrooks Davis #include <sys/param.h>
7294408d94SBrooks Davis #include <sys/systm.h>
7394408d94SBrooks Davis #include <sys/kernel.h>
7494408d94SBrooks Davis #include <sys/malloc.h>
7594408d94SBrooks Davis #include <sys/mbuf.h>
7694408d94SBrooks Davis #include <sys/errno.h>
7794408d94SBrooks Davis #include <sys/syslog.h>
7894408d94SBrooks Davis #include <sys/socket.h>
7994408d94SBrooks Davis 
8094408d94SBrooks Davis #include <net/if.h>
8194408d94SBrooks Davis #include <net/route.h>
8294408d94SBrooks Davis #include <net/if_types.h>
8394408d94SBrooks Davis #include <net/if_var.h>
8494408d94SBrooks Davis #include <net/if_gif.h>
85*3d0d5b21SJustin Hibbits #include <net/if_private.h>
864b79449eSBjoern A. Zeeb #include <net/vnet.h>
8794408d94SBrooks Davis 
8894408d94SBrooks Davis #include <netgraph/ng_message.h>
8994408d94SBrooks Davis #include <netgraph/netgraph.h>
9094408d94SBrooks Davis #include <netgraph/ng_parse.h>
9194408d94SBrooks Davis #include <netgraph/ng_gif.h>
9294408d94SBrooks Davis 
93fc74a9f9SBrooks Davis #define IFP2NG(ifp)  ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph)
94fc74a9f9SBrooks Davis #define IFP2NG_SET(ifp, val)  (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val))
9594408d94SBrooks Davis 
9694408d94SBrooks Davis /* Per-node private data */
9794408d94SBrooks Davis struct private {
9894408d94SBrooks Davis 	struct ifnet	*ifp;		/* associated interface */
9994408d94SBrooks Davis 	hook_p		lower;		/* lower OR orphan hook connection */
10094408d94SBrooks Davis 	u_char		lowerOrphan;	/* whether lower is lower or orphan */
10194408d94SBrooks Davis };
10294408d94SBrooks Davis typedef struct private *priv_p;
10394408d94SBrooks Davis 
10494408d94SBrooks Davis /* Functional hooks called from if_gif.c */
10594408d94SBrooks Davis static void	ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);
10694408d94SBrooks Davis static void	ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);
10794408d94SBrooks Davis static void	ng_gif_attach(struct ifnet *ifp);
10894408d94SBrooks Davis static void	ng_gif_detach(struct ifnet *ifp);
10994408d94SBrooks Davis 
11094408d94SBrooks Davis /* Other functions */
11194408d94SBrooks Davis static void	ng_gif_input2(node_p node, struct mbuf **mp, int af);
11294408d94SBrooks Davis static int	ng_gif_glue_af(struct mbuf **mp, int af);
1133ca24c28SJulian Elischer static int	ng_gif_rcv_lower(node_p node, struct mbuf *m);
11494408d94SBrooks Davis 
11594408d94SBrooks Davis /* Netgraph node methods */
11694408d94SBrooks Davis static ng_constructor_t	ng_gif_constructor;
11794408d94SBrooks Davis static ng_rcvmsg_t	ng_gif_rcvmsg;
11894408d94SBrooks Davis static ng_shutdown_t	ng_gif_shutdown;
11994408d94SBrooks Davis static ng_newhook_t	ng_gif_newhook;
12094408d94SBrooks Davis static ng_connect_t	ng_gif_connect;
12194408d94SBrooks Davis static ng_rcvdata_t	ng_gif_rcvdata;
12294408d94SBrooks Davis static ng_disconnect_t	ng_gif_disconnect;
12394408d94SBrooks Davis static int		ng_gif_mod_event(module_t mod, int event, void *data);
12494408d94SBrooks Davis 
12594408d94SBrooks Davis /* List of commands and how to convert arguments to/from ASCII */
12694408d94SBrooks Davis static const struct ng_cmdlist ng_gif_cmdlist[] = {
12794408d94SBrooks Davis 	{
12894408d94SBrooks Davis 	  NGM_GIF_COOKIE,
12994408d94SBrooks Davis 	  NGM_GIF_GET_IFNAME,
13094408d94SBrooks Davis 	  "getifname",
13194408d94SBrooks Davis 	  NULL,
13294408d94SBrooks Davis 	  &ng_parse_string_type
13394408d94SBrooks Davis 	},
13494408d94SBrooks Davis 	{
13594408d94SBrooks Davis 	  NGM_GIF_COOKIE,
13694408d94SBrooks Davis 	  NGM_GIF_GET_IFINDEX,
13794408d94SBrooks Davis 	  "getifindex",
13894408d94SBrooks Davis 	  NULL,
13994408d94SBrooks Davis 	  &ng_parse_int32_type
14094408d94SBrooks Davis 	},
14194408d94SBrooks Davis 	{ 0 }
14294408d94SBrooks Davis };
14394408d94SBrooks Davis 
14494408d94SBrooks Davis static struct ng_type ng_gif_typestruct = {
145f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
146f8aae777SJulian Elischer 	.name =		NG_GIF_NODE_TYPE,
147f8aae777SJulian Elischer 	.mod_event =	ng_gif_mod_event,
148f8aae777SJulian Elischer 	.constructor =	ng_gif_constructor,
149f8aae777SJulian Elischer 	.rcvmsg =	ng_gif_rcvmsg,
150f8aae777SJulian Elischer 	.shutdown =	ng_gif_shutdown,
151f8aae777SJulian Elischer 	.newhook =	ng_gif_newhook,
152f8aae777SJulian Elischer 	.connect =	ng_gif_connect,
153f8aae777SJulian Elischer 	.rcvdata =	ng_gif_rcvdata,
154f8aae777SJulian Elischer 	.disconnect =	ng_gif_disconnect,
155f8aae777SJulian Elischer 	.cmdlist =	ng_gif_cmdlist,
15694408d94SBrooks Davis };
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 static void
ng_gif_input(struct ifnet * ifp,struct mbuf ** mp,int af)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 static void
ng_gif_input_orphan(struct ifnet * ifp,struct mbuf * m,int af)18594408d94SBrooks Davis ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
18694408d94SBrooks Davis {
18794408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
18894408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
18994408d94SBrooks Davis 
19094408d94SBrooks Davis 	/* If "orphan" hook not connected, let packet continue */
19194408d94SBrooks Davis 	if (priv->lower == NULL || !priv->lowerOrphan) {
19294408d94SBrooks Davis 		m_freem(m);
19394408d94SBrooks Davis 		return;
19494408d94SBrooks Davis 	}
19594408d94SBrooks Davis 	ng_gif_input2(node, &m, af);
19694408d94SBrooks Davis 	if (m != NULL)
19794408d94SBrooks Davis 		m_freem(m);
19894408d94SBrooks Davis }
19994408d94SBrooks Davis 
20094408d94SBrooks Davis /*
20194408d94SBrooks Davis  * Handle a packet that has come in on a gif interface.
20294408d94SBrooks Davis  * Attach the address family to the mbuf for later use.
20394408d94SBrooks Davis  */
20494408d94SBrooks Davis static void
ng_gif_input2(node_p node,struct mbuf ** mp,int af)20594408d94SBrooks Davis ng_gif_input2(node_p node, struct mbuf **mp, int af)
20694408d94SBrooks Davis {
20794408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
20894408d94SBrooks Davis 	int error;
20994408d94SBrooks Davis 
21094408d94SBrooks Davis 	/* Glue address family on */
21194408d94SBrooks Davis 	if ((error = ng_gif_glue_af(mp, af)) != 0)
21294408d94SBrooks Davis 		return;
21394408d94SBrooks Davis 
21494408d94SBrooks Davis 	/* Send out lower/orphan hook */
21594408d94SBrooks Davis 	NG_SEND_DATA_ONLY(error, priv->lower, *mp);
21694408d94SBrooks Davis 	*mp = NULL;
21794408d94SBrooks Davis }
21894408d94SBrooks Davis 
21994408d94SBrooks Davis /*
22094408d94SBrooks Davis  * A new gif interface has been attached.
22194408d94SBrooks Davis  * Create a new node for it, etc.
22294408d94SBrooks Davis  */
22394408d94SBrooks Davis static void
ng_gif_attach(struct ifnet * ifp)22494408d94SBrooks Davis ng_gif_attach(struct ifnet *ifp)
22594408d94SBrooks Davis {
22694408d94SBrooks Davis 	priv_p priv;
22794408d94SBrooks Davis 	node_p node;
22894408d94SBrooks Davis 
22994408d94SBrooks Davis 	/* Create node */
2306e551fb6SDavid E. O'Brien 	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
23194408d94SBrooks Davis 	if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
23294408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2339bf40edeSBrooks Davis 		    __func__, "create node", ifp->if_xname);
23494408d94SBrooks Davis 		return;
23594408d94SBrooks Davis 	}
23694408d94SBrooks Davis 
23794408d94SBrooks Davis 	/* Allocate private data */
2381ede983cSDag-Erling Smørgrav 	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
23994408d94SBrooks Davis 	if (priv == NULL) {
24094408d94SBrooks Davis 		log(LOG_ERR, "%s: can't %s for %s\n",
2419bf40edeSBrooks Davis 		    __func__, "allocate memory", ifp->if_xname);
24294408d94SBrooks Davis 		NG_NODE_UNREF(node);
24394408d94SBrooks Davis 		return;
24494408d94SBrooks Davis 	}
24594408d94SBrooks Davis 	NG_NODE_SET_PRIVATE(node, priv);
24694408d94SBrooks Davis 	priv->ifp = ifp;
247445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, node);
24894408d94SBrooks Davis 
24994408d94SBrooks Davis 	/* Try to give the node the same name as the interface */
2509bf40edeSBrooks Davis 	if (ng_name_node(node, ifp->if_xname) != 0) {
25194408d94SBrooks Davis 		log(LOG_WARNING, "%s: can't name node %s\n",
2529bf40edeSBrooks Davis 		    __func__, ifp->if_xname);
25394408d94SBrooks Davis 	}
25494408d94SBrooks Davis }
25594408d94SBrooks Davis 
25694408d94SBrooks Davis /*
2577360079aSBrooks Davis  * An interface is being detached.
25894408d94SBrooks Davis  * REALLY Destroy its node.
25994408d94SBrooks Davis  */
26094408d94SBrooks Davis static void
ng_gif_detach(struct ifnet * ifp)26194408d94SBrooks Davis ng_gif_detach(struct ifnet *ifp)
26294408d94SBrooks Davis {
26394408d94SBrooks Davis 	const node_p node = IFP2NG(ifp);
264917a7daaSPoul-Henning Kamp 	priv_p priv;
26594408d94SBrooks Davis 
26694408d94SBrooks Davis 	if (node == NULL)		/* no node (why not?), ignore */
26794408d94SBrooks Davis 		return;
2683f54070bSColin Percival 	priv = NG_NODE_PRIVATE(node);
26994408d94SBrooks Davis 	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
27094408d94SBrooks Davis 	/*
27194408d94SBrooks Davis 	 * We can't assume the ifnet is still around when we run shutdown
27294408d94SBrooks Davis 	 * So zap it now. XXX We HOPE that anything running at this time
27394408d94SBrooks Davis 	 * handles it (as it should in the non netgraph case).
27494408d94SBrooks Davis 	 */
275445e045bSAlexander Kabaev 	IFP2NG_SET(ifp, NULL);
27694408d94SBrooks Davis 	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
27794408d94SBrooks Davis 	ng_rmnode_self(node);		/* remove all netgraph parts */
27894408d94SBrooks Davis }
27994408d94SBrooks Davis 
28094408d94SBrooks Davis /*
2817360079aSBrooks Davis  * Optimization for gluing the address family onto
28294408d94SBrooks Davis  * the front of an incoming packet.
28394408d94SBrooks Davis  */
28494408d94SBrooks Davis static int
ng_gif_glue_af(struct mbuf ** mp,int af)28594408d94SBrooks Davis ng_gif_glue_af(struct mbuf **mp, int af)
28694408d94SBrooks Davis {
28794408d94SBrooks Davis 	struct mbuf *m = *mp;
28894408d94SBrooks Davis 	int error = 0;
28994408d94SBrooks Davis 	sa_family_t tmp_af;
29094408d94SBrooks Davis 
29194408d94SBrooks Davis 	tmp_af = (sa_family_t) af;
29294408d94SBrooks Davis 
29394408d94SBrooks Davis 	/*
29494408d94SBrooks Davis 	 * XXX: should try to bring back some of the optimizations from
29594408d94SBrooks Davis 	 * ng_ether.c
29694408d94SBrooks Davis 	 */
29794408d94SBrooks Davis 
29894408d94SBrooks Davis 	/*
29994408d94SBrooks Davis 	 * Doing anything more is likely to get more
30094408d94SBrooks Davis 	 * expensive than it's worth..
30194408d94SBrooks Davis 	 * it's probable that everything else is in one
30294408d94SBrooks Davis 	 * big lump. The next node will do an m_pullup()
30394408d94SBrooks Davis 	 * for exactly the amount of data it needs and
30494408d94SBrooks Davis 	 * hopefully everything after that will not
30594408d94SBrooks Davis 	 * need one. So let's just use M_PREPEND.
30694408d94SBrooks Davis 	 */
307eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof (tmp_af), M_NOWAIT);
30894408d94SBrooks Davis 	if (m == NULL) {
30994408d94SBrooks Davis 		error = ENOBUFS;
31094408d94SBrooks Davis 		goto done;
31194408d94SBrooks Davis 	}
31294408d94SBrooks Davis 
31394408d94SBrooks Davis #if 0
31494408d94SBrooks Davis copy:
31594408d94SBrooks Davis #endif
31694408d94SBrooks Davis 	/* Copy header and return (possibly new) mbuf */
31794408d94SBrooks Davis 	*mtod(m, sa_family_t *) = tmp_af;
31894408d94SBrooks Davis #if 0
31994408d94SBrooks Davis 	bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
32094408d94SBrooks Davis #endif
32194408d94SBrooks Davis done:
32294408d94SBrooks Davis 	*mp = m;
32394408d94SBrooks Davis 	return error;
32494408d94SBrooks Davis }
32594408d94SBrooks Davis 
32694408d94SBrooks Davis /******************************************************************
32794408d94SBrooks Davis 		    NETGRAPH NODE METHODS
32894408d94SBrooks Davis ******************************************************************/
32994408d94SBrooks Davis 
33094408d94SBrooks Davis /*
33194408d94SBrooks Davis  * It is not possible or allowable to create a node of this type.
33294408d94SBrooks Davis  * Nodes get created when the interface is attached (or, when
33394408d94SBrooks Davis  * this node type's KLD is loaded).
33494408d94SBrooks Davis  */
33594408d94SBrooks Davis static int
ng_gif_constructor(node_p node)33694408d94SBrooks Davis ng_gif_constructor(node_p node)
33794408d94SBrooks Davis {
33894408d94SBrooks Davis 	return (EINVAL);
33994408d94SBrooks Davis }
34094408d94SBrooks Davis 
34194408d94SBrooks Davis /*
34294408d94SBrooks Davis  * Check for attaching a new hook.
34394408d94SBrooks Davis  */
34494408d94SBrooks Davis static	int
ng_gif_newhook(node_p node,hook_p hook,const char * name)34594408d94SBrooks Davis ng_gif_newhook(node_p node, hook_p hook, const char *name)
34694408d94SBrooks Davis {
34794408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
34894408d94SBrooks Davis 	u_char orphan = priv->lowerOrphan;
34994408d94SBrooks Davis 	hook_p *hookptr;
35094408d94SBrooks Davis 
35194408d94SBrooks Davis 	/* Divert hook is an alias for lower */
35294408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
35394408d94SBrooks Davis 		name = NG_GIF_HOOK_LOWER;
35494408d94SBrooks Davis 
35594408d94SBrooks Davis 	/* Which hook? */
35694408d94SBrooks Davis 	if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
35794408d94SBrooks Davis 		hookptr = &priv->lower;
35894408d94SBrooks Davis 		orphan = 0;
35994408d94SBrooks Davis 	} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
36094408d94SBrooks Davis 		hookptr = &priv->lower;
36194408d94SBrooks Davis 		orphan = 1;
36294408d94SBrooks Davis 	} else
36394408d94SBrooks Davis 		return (EINVAL);
36494408d94SBrooks Davis 
36594408d94SBrooks Davis 	/* Check if already connected (shouldn't be, but doesn't hurt) */
36694408d94SBrooks Davis 	if (*hookptr != NULL)
36794408d94SBrooks Davis 		return (EISCONN);
36894408d94SBrooks Davis 
36994408d94SBrooks Davis 	/* OK */
37094408d94SBrooks Davis 	*hookptr = hook;
37194408d94SBrooks Davis 	priv->lowerOrphan = orphan;
37294408d94SBrooks Davis 	return (0);
37394408d94SBrooks Davis }
37494408d94SBrooks Davis 
37594408d94SBrooks Davis /*
37694408d94SBrooks Davis  * Hooks are attached, adjust to force queueing.
37794408d94SBrooks Davis  * We don't really care which hook it is.
37894408d94SBrooks Davis  * they should all be queuing for outgoing data.
37994408d94SBrooks Davis  */
38094408d94SBrooks Davis static	int
ng_gif_connect(hook_p hook)38194408d94SBrooks Davis ng_gif_connect(hook_p hook)
38294408d94SBrooks Davis {
38394408d94SBrooks Davis 	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
38494408d94SBrooks Davis 	return (0);
38594408d94SBrooks Davis }
38694408d94SBrooks Davis 
38794408d94SBrooks Davis /*
38894408d94SBrooks Davis  * Receive an incoming control message.
38994408d94SBrooks Davis  */
39094408d94SBrooks Davis static int
ng_gif_rcvmsg(node_p node,item_p item,hook_p lasthook)39194408d94SBrooks Davis ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
39294408d94SBrooks Davis {
39394408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
39494408d94SBrooks Davis 	struct ng_mesg *resp = NULL;
39594408d94SBrooks Davis 	int error = 0;
39694408d94SBrooks Davis 	struct ng_mesg *msg;
39794408d94SBrooks Davis 
39894408d94SBrooks Davis 	NGI_GET_MSG(item, msg);
39994408d94SBrooks Davis 	switch (msg->header.typecookie) {
40094408d94SBrooks Davis 	case NGM_GIF_COOKIE:
40194408d94SBrooks Davis 		switch (msg->header.cmd) {
40294408d94SBrooks Davis 		case NGM_GIF_GET_IFNAME:
403bbb75d78SRuslan Ermilov 			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
40494408d94SBrooks Davis 			if (resp == NULL) {
40594408d94SBrooks Davis 				error = ENOMEM;
40694408d94SBrooks Davis 				break;
40794408d94SBrooks Davis 			}
408bbb75d78SRuslan Ermilov 			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
40994408d94SBrooks Davis 			break;
41094408d94SBrooks Davis 		case NGM_GIF_GET_IFINDEX:
41194408d94SBrooks Davis 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
41294408d94SBrooks Davis 			if (resp == NULL) {
41394408d94SBrooks Davis 				error = ENOMEM;
41494408d94SBrooks Davis 				break;
41594408d94SBrooks Davis 			}
41694408d94SBrooks Davis 			*((u_int32_t *)resp->data) = priv->ifp->if_index;
41794408d94SBrooks Davis 			break;
41894408d94SBrooks Davis 		default:
41994408d94SBrooks Davis 			error = EINVAL;
42094408d94SBrooks Davis 			break;
42194408d94SBrooks Davis 		}
42294408d94SBrooks Davis 		break;
42394408d94SBrooks Davis 	default:
42494408d94SBrooks Davis 		error = EINVAL;
42594408d94SBrooks Davis 		break;
42694408d94SBrooks Davis 	}
42794408d94SBrooks Davis 	NG_RESPOND_MSG(error, node, item, resp);
42894408d94SBrooks Davis 	NG_FREE_MSG(msg);
42994408d94SBrooks Davis 	return (error);
43094408d94SBrooks Davis }
43194408d94SBrooks Davis 
43294408d94SBrooks Davis /*
43394408d94SBrooks Davis  * Receive data on a hook.
43494408d94SBrooks Davis  */
43594408d94SBrooks Davis static int
ng_gif_rcvdata(hook_p hook,item_p item)43694408d94SBrooks Davis ng_gif_rcvdata(hook_p hook, item_p item)
43794408d94SBrooks Davis {
43894408d94SBrooks Davis 	const node_p node = NG_HOOK_NODE(hook);
43994408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
44094408d94SBrooks Davis 	struct mbuf *m;
44194408d94SBrooks Davis 
44294408d94SBrooks Davis 	NGI_GET_M(item, m);
44394408d94SBrooks Davis 	NG_FREE_ITEM(item);
4443ca24c28SJulian Elischer 
44594408d94SBrooks Davis 	if (hook == priv->lower)
4463ca24c28SJulian Elischer 		return ng_gif_rcv_lower(node, m);
4476e551fb6SDavid E. O'Brien 	panic("%s: weird hook", __func__);
44894408d94SBrooks Davis }
44994408d94SBrooks Davis 
45094408d94SBrooks Davis /*
45194408d94SBrooks Davis  * Handle an mbuf received on the "lower" hook.
45294408d94SBrooks Davis  */
45394408d94SBrooks Davis static int
ng_gif_rcv_lower(node_p node,struct mbuf * m)4543ca24c28SJulian Elischer ng_gif_rcv_lower(node_p node, struct mbuf *m)
45594408d94SBrooks Davis {
45694408d94SBrooks Davis 	struct sockaddr	dst;
45794408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
45894408d94SBrooks Davis 
45994408d94SBrooks Davis 	bzero(&dst, sizeof(dst));
46094408d94SBrooks Davis 
46194408d94SBrooks Davis 	/* Make sure header is fully pulled up */
46294408d94SBrooks Davis 	if (m->m_pkthdr.len < sizeof(sa_family_t)) {
46394408d94SBrooks Davis 		NG_FREE_M(m);
46494408d94SBrooks Davis 		return (EINVAL);
46594408d94SBrooks Davis 	}
46694408d94SBrooks Davis 	if (m->m_len < sizeof(sa_family_t)
46794408d94SBrooks Davis 	    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
46894408d94SBrooks Davis 		return (ENOBUFS);
46994408d94SBrooks Davis 	}
47094408d94SBrooks Davis 
47194408d94SBrooks Davis 	dst.sa_family = *mtod(m, sa_family_t *);
47294408d94SBrooks Davis 	m_adj(m, sizeof(sa_family_t));
47394408d94SBrooks Davis 
47494408d94SBrooks Davis 	/* Send it on its way */
47594408d94SBrooks Davis 	/*
47694408d94SBrooks Davis 	 * XXX: gif_output only uses dst for the family and passes the
47794408d94SBrooks Davis 	 * fourth argument (rt) to in{,6}_gif_output which ignore it.
47894408d94SBrooks Davis 	 * If this changes ng_gif will probably break.
47994408d94SBrooks Davis 	 */
48094408d94SBrooks Davis 	return gif_output(priv->ifp, m, &dst, NULL);
48194408d94SBrooks Davis }
48294408d94SBrooks Davis 
48394408d94SBrooks Davis /*
48494408d94SBrooks Davis  * Shutdown node. This resets the node but does not remove it
48594408d94SBrooks Davis  * unless the REALLY_DIE flag is set.
48694408d94SBrooks Davis  */
48794408d94SBrooks Davis static int
ng_gif_shutdown(node_p node)48894408d94SBrooks Davis ng_gif_shutdown(node_p node)
48994408d94SBrooks Davis {
49094408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(node);
49194408d94SBrooks Davis 
492be4252b3SJulian Elischer 	if (node->nd_flags & NGF_REALLY_DIE) {
49394408d94SBrooks Davis 		/*
49494408d94SBrooks Davis 		 * WE came here because the gif interface is being destroyed,
495053359b7SPedro F. Giffuni 		 * so stop being persistent.
49694408d94SBrooks Davis 		 * Actually undo all the things we did on creation.
49794408d94SBrooks Davis 		 * Assume the ifp has already been freed.
49894408d94SBrooks Davis 		 */
49994408d94SBrooks Davis 		NG_NODE_SET_PRIVATE(node, NULL);
5001ede983cSDag-Erling Smørgrav 		free(priv, M_NETGRAPH);
50194408d94SBrooks Davis 		NG_NODE_UNREF(node);	/* free node itself */
50294408d94SBrooks Davis 		return (0);
50394408d94SBrooks Davis 	}
504be4252b3SJulian Elischer 	NG_NODE_REVIVE(node);		/* Signal ng_rmnode we are persisant */
50594408d94SBrooks Davis 	return (0);
50694408d94SBrooks Davis }
50794408d94SBrooks Davis 
50894408d94SBrooks Davis /*
50994408d94SBrooks Davis  * Hook disconnection.
51094408d94SBrooks Davis  */
51194408d94SBrooks Davis static int
ng_gif_disconnect(hook_p hook)51294408d94SBrooks Davis ng_gif_disconnect(hook_p hook)
51394408d94SBrooks Davis {
51494408d94SBrooks Davis 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
51594408d94SBrooks Davis 
51694408d94SBrooks Davis 	if (hook == priv->lower) {
51794408d94SBrooks Davis 		priv->lower = NULL;
51894408d94SBrooks Davis 		priv->lowerOrphan = 0;
51994408d94SBrooks Davis 	} else
5206e551fb6SDavid E. O'Brien 		panic("%s: weird hook", __func__);
52194408d94SBrooks Davis 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
52294408d94SBrooks Davis 	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
52394408d94SBrooks Davis 		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
52494408d94SBrooks Davis 
52594408d94SBrooks Davis 	return (0);
52694408d94SBrooks Davis }
52794408d94SBrooks Davis 
52894408d94SBrooks Davis /******************************************************************
52994408d94SBrooks Davis 		    	INITIALIZATION
53094408d94SBrooks Davis ******************************************************************/
53194408d94SBrooks Davis 
53294408d94SBrooks Davis /*
53394408d94SBrooks Davis  * Handle loading and unloading for this node type.
53494408d94SBrooks Davis  */
53594408d94SBrooks Davis static int
ng_gif_mod_event(module_t mod,int event,void * data)53694408d94SBrooks Davis ng_gif_mod_event(module_t mod, int event, void *data)
53794408d94SBrooks Davis {
5388b615593SMarko Zec 	VNET_ITERATOR_DECL(vnet_iter);
53994408d94SBrooks Davis 	struct ifnet *ifp;
54094408d94SBrooks Davis 	int error = 0;
54194408d94SBrooks Davis 
54294408d94SBrooks Davis 	switch (event) {
54394408d94SBrooks Davis 	case MOD_LOAD:
54494408d94SBrooks Davis 
54594408d94SBrooks Davis 		/* Register function hooks */
54694408d94SBrooks Davis 		if (ng_gif_attach_p != NULL) {
54794408d94SBrooks Davis 			error = EEXIST;
54894408d94SBrooks Davis 			break;
54994408d94SBrooks Davis 		}
55094408d94SBrooks Davis 		ng_gif_attach_p = ng_gif_attach;
55194408d94SBrooks Davis 		ng_gif_detach_p = ng_gif_detach;
55294408d94SBrooks Davis 		ng_gif_input_p = ng_gif_input;
55394408d94SBrooks Davis 		ng_gif_input_orphan_p = ng_gif_input_orphan;
55494408d94SBrooks Davis 
55594408d94SBrooks Davis 		/* Create nodes for any already-existing gif interfaces */
55677dfcdc4SRobert Watson 		VNET_LIST_RLOCK();
557b30a244cSJeffrey Hsu 		IFNET_RLOCK();
5588b615593SMarko Zec 		VNET_FOREACH(vnet_iter) {
5598b615593SMarko Zec 			CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */
5604560b78dSJohn Baldwin 			CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
56194408d94SBrooks Davis 				if (ifp->if_type == IFT_GIF)
56294408d94SBrooks Davis 					ng_gif_attach(ifp);
56394408d94SBrooks Davis 			}
5648b615593SMarko Zec 			CURVNET_RESTORE();
5658b615593SMarko Zec 		}
566b30a244cSJeffrey Hsu 		IFNET_RUNLOCK();
56777dfcdc4SRobert Watson 		VNET_LIST_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 	return (error);
59494408d94SBrooks Davis }
595