183998Sbrooks/*
283998Sbrooks * ng_gif.c
3139823Simp */
4139823Simp
5139823Simp/*-
683998Sbrooks * Copyright 2001 The Aerospace Corporation.  All rights reserved.
783998Sbrooks *
883998Sbrooks * Redistribution and use in source and binary forms, with or without
983998Sbrooks * modification, are permitted provided that the following conditions
1083998Sbrooks * are met:
1184000Sbrooks *
1283998Sbrooks * 1. Redistributions of source code must retain the above copyright
1384000Sbrooks *    notice, this list of conditions, and the following disclaimer.
1483998Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
1584000Sbrooks *    notice, this list of conditions, and the following disclaimer in the
1683998Sbrooks *    documentation and/or other materials provided with the distribution.
1784000Sbrooks * 3. The name of The Aerospace Corporation may not be used to endorse or
1884000Sbrooks *    promote products derived from this software.
1983998Sbrooks *
2083998Sbrooks * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
2183998Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2283998Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2383998Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
2483998Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2583998Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2683998Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2783998Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2883998Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2983998Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3083998Sbrooks * SUCH DAMAGE.
3183998Sbrooks *
3283998Sbrooks *
3383998Sbrooks * Copyright (c) 1996-2000 Whistle Communications, Inc.
3483998Sbrooks * All rights reserved.
3583998Sbrooks *
3683998Sbrooks * Subject to the following obligations and disclaimer of warranty, use and
3783998Sbrooks * redistribution of this software, in source or object code forms, with or
3883998Sbrooks * without modifications are expressly permitted by Whistle Communications;
3983998Sbrooks * provided, however, that:
4083998Sbrooks * 1. Any and all reproductions of the source or object code must include the
4183998Sbrooks *    copyright notice above and the following disclaimer of warranties; and
4283998Sbrooks * 2. No rights are granted, in any manner or form, to use Whistle
4383998Sbrooks *    Communications, Inc. trademarks, including the mark "WHISTLE
4483998Sbrooks *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
4583998Sbrooks *    such appears in the above copyright notice or in the software.
4683998Sbrooks *
4783998Sbrooks * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
4883998Sbrooks * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
4983998Sbrooks * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
5083998Sbrooks * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
5183998Sbrooks * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
5283998Sbrooks * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
5383998Sbrooks * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
5483998Sbrooks * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
5583998Sbrooks * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
5683998Sbrooks * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
5783998Sbrooks * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
5883998Sbrooks * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
5983998Sbrooks * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
6083998Sbrooks * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6183998Sbrooks * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
6283998Sbrooks * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
6383998Sbrooks * OF SUCH DAMAGE.
6483998Sbrooks *
6583998Sbrooks * $FreeBSD$
6683998Sbrooks */
6783998Sbrooks
6883998Sbrooks/*
6983998Sbrooks * ng_gif(4) netgraph node type
7083998Sbrooks */
7183998Sbrooks#include <sys/param.h>
7283998Sbrooks#include <sys/systm.h>
7383998Sbrooks#include <sys/kernel.h>
7483998Sbrooks#include <sys/malloc.h>
7583998Sbrooks#include <sys/mbuf.h>
7683998Sbrooks#include <sys/errno.h>
7783998Sbrooks#include <sys/syslog.h>
7883998Sbrooks#include <sys/socket.h>
7983998Sbrooks
8083998Sbrooks#include <net/if.h>
8183998Sbrooks#include <net/route.h>
8283998Sbrooks#include <net/if_types.h>
8383998Sbrooks#include <net/if_var.h>
8483998Sbrooks#include <net/if_gif.h>
85185571Sbz#include <net/vnet.h>
8683998Sbrooks
8783998Sbrooks#include <netgraph/ng_message.h>
8883998Sbrooks#include <netgraph/netgraph.h>
8983998Sbrooks#include <netgraph/ng_parse.h>
9083998Sbrooks#include <netgraph/ng_gif.h>
9183998Sbrooks
92147256Sbrooks#define IFP2NG(ifp)  ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph)
93147256Sbrooks#define IFP2NG_SET(ifp, val)  (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val))
9483998Sbrooks
9583998Sbrooks/* Per-node private data */
9683998Sbrooksstruct private {
9783998Sbrooks	struct ifnet	*ifp;		/* associated interface */
9883998Sbrooks	hook_p		lower;		/* lower OR orphan hook connection */
9983998Sbrooks	u_char		lowerOrphan;	/* whether lower is lower or orphan */
10083998Sbrooks};
10183998Sbrookstypedef struct private *priv_p;
10283998Sbrooks
10383998Sbrooks/* Functional hooks called from if_gif.c */
10483998Sbrooksstatic void	ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);
10583998Sbrooksstatic void	ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);
10683998Sbrooksstatic void	ng_gif_attach(struct ifnet *ifp);
10783998Sbrooksstatic void	ng_gif_detach(struct ifnet *ifp);
10883998Sbrooks
10983998Sbrooks/* Other functions */
11083998Sbrooksstatic void	ng_gif_input2(node_p node, struct mbuf **mp, int af);
11183998Sbrooksstatic int	ng_gif_glue_af(struct mbuf **mp, int af);
112131155Sjulianstatic int	ng_gif_rcv_lower(node_p node, struct mbuf *m);
11383998Sbrooks
11483998Sbrooks/* Netgraph node methods */
11583998Sbrooksstatic ng_constructor_t	ng_gif_constructor;
11683998Sbrooksstatic ng_rcvmsg_t	ng_gif_rcvmsg;
11783998Sbrooksstatic ng_shutdown_t	ng_gif_shutdown;
11883998Sbrooksstatic ng_newhook_t	ng_gif_newhook;
11983998Sbrooksstatic ng_connect_t	ng_gif_connect;
12083998Sbrooksstatic ng_rcvdata_t	ng_gif_rcvdata;
12183998Sbrooksstatic ng_disconnect_t	ng_gif_disconnect;
12283998Sbrooksstatic int		ng_gif_mod_event(module_t mod, int event, void *data);
12383998Sbrooks
12483998Sbrooks/* List of commands and how to convert arguments to/from ASCII */
12583998Sbrooksstatic const struct ng_cmdlist ng_gif_cmdlist[] = {
12683998Sbrooks	{
12783998Sbrooks	  NGM_GIF_COOKIE,
12883998Sbrooks	  NGM_GIF_GET_IFNAME,
12983998Sbrooks	  "getifname",
13083998Sbrooks	  NULL,
13183998Sbrooks	  &ng_parse_string_type
13283998Sbrooks	},
13383998Sbrooks	{
13483998Sbrooks	  NGM_GIF_COOKIE,
13583998Sbrooks	  NGM_GIF_GET_IFINDEX,
13683998Sbrooks	  "getifindex",
13783998Sbrooks	  NULL,
13883998Sbrooks	  &ng_parse_int32_type
13983998Sbrooks	},
14083998Sbrooks	{ 0 }
14183998Sbrooks};
14283998Sbrooks
14383998Sbrooksstatic struct ng_type ng_gif_typestruct = {
144129823Sjulian	.version =	NG_ABI_VERSION,
145129823Sjulian	.name =		NG_GIF_NODE_TYPE,
146129823Sjulian	.mod_event =	ng_gif_mod_event,
147129823Sjulian	.constructor =	ng_gif_constructor,
148129823Sjulian	.rcvmsg =	ng_gif_rcvmsg,
149129823Sjulian	.shutdown =	ng_gif_shutdown,
150129823Sjulian	.newhook =	ng_gif_newhook,
151129823Sjulian	.connect =	ng_gif_connect,
152129823Sjulian	.rcvdata =	ng_gif_rcvdata,
153129823Sjulian	.disconnect =	ng_gif_disconnect,
154129823Sjulian	.cmdlist =	ng_gif_cmdlist,
15583998Sbrooks};
15683998SbrooksMODULE_DEPEND(ng_gif, if_gif, 1,1,1);
15783998SbrooksNETGRAPH_INIT(gif, &ng_gif_typestruct);
15883998Sbrooks
15983998Sbrooks/******************************************************************
16083998Sbrooks		       GIF FUNCTION HOOKS
16183998Sbrooks******************************************************************/
16283998Sbrooks
16383998Sbrooks/*
16483998Sbrooks * Handle a packet that has come in on an interface. We get to
16583998Sbrooks * look at it here before any upper layer protocols do.
16683998Sbrooks */
16783998Sbrooksstatic void
16883998Sbrooksng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)
16983998Sbrooks{
17083998Sbrooks	const node_p node = IFP2NG(ifp);
17183998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
17283998Sbrooks
17383998Sbrooks	/* If "lower" hook not connected, let packet continue */
17483998Sbrooks	if (priv->lower == NULL || priv->lowerOrphan)
17583998Sbrooks		return;
17683998Sbrooks	ng_gif_input2(node, mp, af);
17783998Sbrooks}
17883998Sbrooks
17983998Sbrooks/*
18083998Sbrooks * Handle a packet that has come in on an interface, and which
18183998Sbrooks * does not match any of our known protocols (an ``orphan'').
18283998Sbrooks */
18383998Sbrooksstatic void
18483998Sbrooksng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
18583998Sbrooks{
18683998Sbrooks	const node_p node = IFP2NG(ifp);
18783998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
18883998Sbrooks
18983998Sbrooks	/* If "orphan" hook not connected, let packet continue */
19083998Sbrooks	if (priv->lower == NULL || !priv->lowerOrphan) {
19183998Sbrooks		m_freem(m);
19283998Sbrooks		return;
19383998Sbrooks	}
19483998Sbrooks	ng_gif_input2(node, &m, af);
19583998Sbrooks	if (m != NULL)
19683998Sbrooks		m_freem(m);
19783998Sbrooks}
19883998Sbrooks
19983998Sbrooks/*
20083998Sbrooks * Handle a packet that has come in on a gif interface.
20183998Sbrooks * Attach the address family to the mbuf for later use.
20283998Sbrooks */
20383998Sbrooksstatic void
20483998Sbrooksng_gif_input2(node_p node, struct mbuf **mp, int af)
20583998Sbrooks{
20683998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
20783998Sbrooks	int error;
20883998Sbrooks
20983998Sbrooks	/* Glue address family on */
21083998Sbrooks	if ((error = ng_gif_glue_af(mp, af)) != 0)
21183998Sbrooks		return;
21283998Sbrooks
21383998Sbrooks	/* Send out lower/orphan hook */
21483998Sbrooks	NG_SEND_DATA_ONLY(error, priv->lower, *mp);
21583998Sbrooks	*mp = NULL;
21683998Sbrooks}
21783998Sbrooks
21883998Sbrooks/*
21983998Sbrooks * A new gif interface has been attached.
22083998Sbrooks * Create a new node for it, etc.
22183998Sbrooks */
22283998Sbrooksstatic void
22383998Sbrooksng_gif_attach(struct ifnet *ifp)
22483998Sbrooks{
22583998Sbrooks	priv_p priv;
22683998Sbrooks	node_p node;
22783998Sbrooks
22883998Sbrooks	/* Create node */
22987599Sobrien	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
23083998Sbrooks	if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
23183998Sbrooks		log(LOG_ERR, "%s: can't %s for %s\n",
232121816Sbrooks		    __func__, "create node", ifp->if_xname);
23383998Sbrooks		return;
23483998Sbrooks	}
23583998Sbrooks
23683998Sbrooks	/* Allocate private data */
237184205Sdes	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
23883998Sbrooks	if (priv == NULL) {
23983998Sbrooks		log(LOG_ERR, "%s: can't %s for %s\n",
240121816Sbrooks		    __func__, "allocate memory", ifp->if_xname);
24183998Sbrooks		NG_NODE_UNREF(node);
24283998Sbrooks		return;
24383998Sbrooks	}
24483998Sbrooks	NG_NODE_SET_PRIVATE(node, priv);
24583998Sbrooks	priv->ifp = ifp;
246132780Skan	IFP2NG_SET(ifp, node);
24783998Sbrooks
24883998Sbrooks	/* Try to give the node the same name as the interface */
249121816Sbrooks	if (ng_name_node(node, ifp->if_xname) != 0) {
25083998Sbrooks		log(LOG_WARNING, "%s: can't name node %s\n",
251121816Sbrooks		    __func__, ifp->if_xname);
25283998Sbrooks	}
25383998Sbrooks}
25483998Sbrooks
25583998Sbrooks/*
25684060Sbrooks * An interface is being detached.
25783998Sbrooks * REALLY Destroy its node.
25883998Sbrooks */
25983998Sbrooksstatic void
26083998Sbrooksng_gif_detach(struct ifnet *ifp)
26183998Sbrooks{
26283998Sbrooks	const node_p node = IFP2NG(ifp);
263126203Sphk	priv_p priv;
26483998Sbrooks
26583998Sbrooks	if (node == NULL)		/* no node (why not?), ignore */
26683998Sbrooks		return;
267126196Scperciva	priv = NG_NODE_PRIVATE(node);
26883998Sbrooks	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
26983998Sbrooks	/*
27083998Sbrooks	 * We can't assume the ifnet is still around when we run shutdown
27183998Sbrooks	 * So zap it now. XXX We HOPE that anything running at this time
27283998Sbrooks	 * handles it (as it should in the non netgraph case).
27383998Sbrooks	 */
274132780Skan	IFP2NG_SET(ifp, NULL);
27583998Sbrooks	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
27683998Sbrooks	ng_rmnode_self(node);		/* remove all netgraph parts */
27783998Sbrooks}
27883998Sbrooks
27983998Sbrooks/*
28084060Sbrooks * Optimization for gluing the address family onto
28183998Sbrooks * the front of an incoming packet.
28283998Sbrooks */
28383998Sbrooksstatic int
28483998Sbrooksng_gif_glue_af(struct mbuf **mp, int af)
28583998Sbrooks{
28683998Sbrooks	struct mbuf *m = *mp;
28783998Sbrooks	int error = 0;
28883998Sbrooks	sa_family_t tmp_af;
28983998Sbrooks
29083998Sbrooks	tmp_af = (sa_family_t) af;
29183998Sbrooks
29283998Sbrooks	/*
29383998Sbrooks	 * XXX: should try to bring back some of the optimizations from
29483998Sbrooks	 * ng_ether.c
29583998Sbrooks	 */
29683998Sbrooks
29783998Sbrooks	/*
29883998Sbrooks	 * Doing anything more is likely to get more
29983998Sbrooks	 * expensive than it's worth..
30083998Sbrooks	 * it's probable that everything else is in one
30183998Sbrooks	 * big lump. The next node will do an m_pullup()
30283998Sbrooks	 * for exactly the amount of data it needs and
30383998Sbrooks	 * hopefully everything after that will not
30483998Sbrooks	 * need one. So let's just use M_PREPEND.
30583998Sbrooks	 */
306243882Sglebius	M_PREPEND(m, sizeof (tmp_af), M_NOWAIT);
30783998Sbrooks	if (m == NULL) {
30883998Sbrooks		error = ENOBUFS;
30983998Sbrooks		goto done;
31083998Sbrooks	}
31183998Sbrooks
31283998Sbrooks#if 0
31383998Sbrookscopy:
31483998Sbrooks#endif
31583998Sbrooks	/* Copy header and return (possibly new) mbuf */
31683998Sbrooks	*mtod(m, sa_family_t *) = tmp_af;
31783998Sbrooks#if 0
31883998Sbrooks	bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
31983998Sbrooks#endif
32083998Sbrooksdone:
32183998Sbrooks	*mp = m;
32283998Sbrooks	return error;
32383998Sbrooks}
32483998Sbrooks
32583998Sbrooks/******************************************************************
32683998Sbrooks		    NETGRAPH NODE METHODS
32783998Sbrooks******************************************************************/
32883998Sbrooks
32983998Sbrooks/*
33083998Sbrooks * It is not possible or allowable to create a node of this type.
33183998Sbrooks * Nodes get created when the interface is attached (or, when
33283998Sbrooks * this node type's KLD is loaded).
33383998Sbrooks */
33483998Sbrooksstatic int
33583998Sbrooksng_gif_constructor(node_p node)
33683998Sbrooks{
33783998Sbrooks	return (EINVAL);
33883998Sbrooks}
33983998Sbrooks
34083998Sbrooks/*
34183998Sbrooks * Check for attaching a new hook.
34283998Sbrooks */
34383998Sbrooksstatic	int
34483998Sbrooksng_gif_newhook(node_p node, hook_p hook, const char *name)
34583998Sbrooks{
34683998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
34783998Sbrooks	u_char orphan = priv->lowerOrphan;
34883998Sbrooks	hook_p *hookptr;
34983998Sbrooks
35083998Sbrooks	/* Divert hook is an alias for lower */
35183998Sbrooks	if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
35283998Sbrooks		name = NG_GIF_HOOK_LOWER;
35383998Sbrooks
35483998Sbrooks	/* Which hook? */
35583998Sbrooks	if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
35683998Sbrooks		hookptr = &priv->lower;
35783998Sbrooks		orphan = 0;
35883998Sbrooks	} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
35983998Sbrooks		hookptr = &priv->lower;
36083998Sbrooks		orphan = 1;
36183998Sbrooks	} else
36283998Sbrooks		return (EINVAL);
36383998Sbrooks
36483998Sbrooks	/* Check if already connected (shouldn't be, but doesn't hurt) */
36583998Sbrooks	if (*hookptr != NULL)
36683998Sbrooks		return (EISCONN);
36783998Sbrooks
36883998Sbrooks	/* OK */
36983998Sbrooks	*hookptr = hook;
37083998Sbrooks	priv->lowerOrphan = orphan;
37183998Sbrooks	return (0);
37283998Sbrooks}
37383998Sbrooks
37483998Sbrooks/*
37583998Sbrooks * Hooks are attached, adjust to force queueing.
37683998Sbrooks * We don't really care which hook it is.
37783998Sbrooks * they should all be queuing for outgoing data.
37883998Sbrooks */
37983998Sbrooksstatic	int
38083998Sbrooksng_gif_connect(hook_p hook)
38183998Sbrooks{
38283998Sbrooks	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
38383998Sbrooks	return (0);
38483998Sbrooks}
38583998Sbrooks
38683998Sbrooks/*
38783998Sbrooks * Receive an incoming control message.
38883998Sbrooks */
38983998Sbrooksstatic int
39083998Sbrooksng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
39183998Sbrooks{
39283998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
39383998Sbrooks	struct ng_mesg *resp = NULL;
39483998Sbrooks	int error = 0;
39583998Sbrooks	struct ng_mesg *msg;
39683998Sbrooks
39783998Sbrooks	NGI_GET_MSG(item, msg);
39883998Sbrooks	switch (msg->header.typecookie) {
39983998Sbrooks	case NGM_GIF_COOKIE:
40083998Sbrooks		switch (msg->header.cmd) {
40183998Sbrooks		case NGM_GIF_GET_IFNAME:
402141195Sru			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
40383998Sbrooks			if (resp == NULL) {
40483998Sbrooks				error = ENOMEM;
40583998Sbrooks				break;
40683998Sbrooks			}
407141195Sru			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
40883998Sbrooks			break;
40983998Sbrooks		case NGM_GIF_GET_IFINDEX:
41083998Sbrooks			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
41183998Sbrooks			if (resp == NULL) {
41283998Sbrooks				error = ENOMEM;
41383998Sbrooks				break;
41483998Sbrooks			}
41583998Sbrooks			*((u_int32_t *)resp->data) = priv->ifp->if_index;
41683998Sbrooks			break;
41783998Sbrooks		default:
41883998Sbrooks			error = EINVAL;
41983998Sbrooks			break;
42083998Sbrooks		}
42183998Sbrooks		break;
42283998Sbrooks	default:
42383998Sbrooks		error = EINVAL;
42483998Sbrooks		break;
42583998Sbrooks	}
42683998Sbrooks	NG_RESPOND_MSG(error, node, item, resp);
42783998Sbrooks	NG_FREE_MSG(msg);
42883998Sbrooks	return (error);
42983998Sbrooks}
43083998Sbrooks
43183998Sbrooks/*
43283998Sbrooks * Receive data on a hook.
43383998Sbrooks */
43483998Sbrooksstatic int
43583998Sbrooksng_gif_rcvdata(hook_p hook, item_p item)
43683998Sbrooks{
43783998Sbrooks	const node_p node = NG_HOOK_NODE(hook);
43883998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
43983998Sbrooks	struct mbuf *m;
44083998Sbrooks
44183998Sbrooks	NGI_GET_M(item, m);
44283998Sbrooks	NG_FREE_ITEM(item);
443131155Sjulian
44483998Sbrooks	if (hook == priv->lower)
445131155Sjulian		return ng_gif_rcv_lower(node, m);
44687599Sobrien	panic("%s: weird hook", __func__);
44783998Sbrooks}
44883998Sbrooks
44983998Sbrooks/*
45083998Sbrooks * Handle an mbuf received on the "lower" hook.
45183998Sbrooks */
45283998Sbrooksstatic int
453131155Sjulianng_gif_rcv_lower(node_p node, struct mbuf *m)
45483998Sbrooks{
45583998Sbrooks	struct sockaddr	dst;
45683998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
45783998Sbrooks
45883998Sbrooks	bzero(&dst, sizeof(dst));
45983998Sbrooks
46083998Sbrooks	/* Make sure header is fully pulled up */
46183998Sbrooks	if (m->m_pkthdr.len < sizeof(sa_family_t)) {
46283998Sbrooks		NG_FREE_M(m);
46383998Sbrooks		return (EINVAL);
46483998Sbrooks	}
46583998Sbrooks	if (m->m_len < sizeof(sa_family_t)
46683998Sbrooks	    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
46783998Sbrooks		return (ENOBUFS);
46883998Sbrooks	}
46983998Sbrooks
47083998Sbrooks	dst.sa_family = *mtod(m, sa_family_t *);
47183998Sbrooks	m_adj(m, sizeof(sa_family_t));
47283998Sbrooks
47383998Sbrooks	/* Send it on its way */
47483998Sbrooks	/*
47583998Sbrooks	 * XXX: gif_output only uses dst for the family and passes the
47683998Sbrooks	 * fourth argument (rt) to in{,6}_gif_output which ignore it.
47783998Sbrooks	 * If this changes ng_gif will probably break.
47883998Sbrooks	 */
47983998Sbrooks	return gif_output(priv->ifp, m, &dst, NULL);
48083998Sbrooks}
48183998Sbrooks
48283998Sbrooks/*
48383998Sbrooks * Shutdown node. This resets the node but does not remove it
48483998Sbrooks * unless the REALLY_DIE flag is set.
48583998Sbrooks */
48683998Sbrooksstatic int
48783998Sbrooksng_gif_shutdown(node_p node)
48883998Sbrooks{
48983998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
49083998Sbrooks
491132464Sjulian	if (node->nd_flags & NGF_REALLY_DIE) {
49283998Sbrooks		/*
49383998Sbrooks		 * WE came here because the gif interface is being destroyed,
49483998Sbrooks		 * so stop being persistant.
49583998Sbrooks		 * Actually undo all the things we did on creation.
49683998Sbrooks		 * Assume the ifp has already been freed.
49783998Sbrooks		 */
49883998Sbrooks		NG_NODE_SET_PRIVATE(node, NULL);
499184205Sdes		free(priv, M_NETGRAPH);
50083998Sbrooks		NG_NODE_UNREF(node);	/* free node itself */
50183998Sbrooks		return (0);
50283998Sbrooks	}
503132464Sjulian	NG_NODE_REVIVE(node);		/* Signal ng_rmnode we are persisant */
50483998Sbrooks	return (0);
50583998Sbrooks}
50683998Sbrooks
50783998Sbrooks/*
50883998Sbrooks * Hook disconnection.
50983998Sbrooks */
51083998Sbrooksstatic int
51183998Sbrooksng_gif_disconnect(hook_p hook)
51283998Sbrooks{
51383998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
51483998Sbrooks
51583998Sbrooks	if (hook == priv->lower) {
51683998Sbrooks		priv->lower = NULL;
51783998Sbrooks		priv->lowerOrphan = 0;
51883998Sbrooks	} else
51987599Sobrien		panic("%s: weird hook", __func__);
52083998Sbrooks	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
52183998Sbrooks	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
52283998Sbrooks		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
52383998Sbrooks
52483998Sbrooks	return (0);
52583998Sbrooks}
52683998Sbrooks
52783998Sbrooks/******************************************************************
52883998Sbrooks		    	INITIALIZATION
52983998Sbrooks******************************************************************/
53083998Sbrooks
53183998Sbrooks/*
53283998Sbrooks * Handle loading and unloading for this node type.
53383998Sbrooks */
53483998Sbrooksstatic int
53583998Sbrooksng_gif_mod_event(module_t mod, int event, void *data)
53683998Sbrooks{
537183550Szec	VNET_ITERATOR_DECL(vnet_iter);
53883998Sbrooks	struct ifnet *ifp;
53983998Sbrooks	int error = 0;
54083998Sbrooks
54183998Sbrooks	switch (event) {
54283998Sbrooks	case MOD_LOAD:
54383998Sbrooks
54483998Sbrooks		/* Register function hooks */
54583998Sbrooks		if (ng_gif_attach_p != NULL) {
54683998Sbrooks			error = EEXIST;
54783998Sbrooks			break;
54883998Sbrooks		}
54983998Sbrooks		ng_gif_attach_p = ng_gif_attach;
55083998Sbrooks		ng_gif_detach_p = ng_gif_detach;
55183998Sbrooks		ng_gif_input_p = ng_gif_input;
55283998Sbrooks		ng_gif_input_orphan_p = ng_gif_input_orphan;
55383998Sbrooks
55483998Sbrooks		/* Create nodes for any already-existing gif interfaces */
555196481Srwatson		VNET_LIST_RLOCK();
556108172Shsu		IFNET_RLOCK();
557183550Szec		VNET_FOREACH(vnet_iter) {
558183550Szec			CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */
559183550Szec			TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
560183550Szec				if (ifp->if_type == IFT_GIF)
561183550Szec					ng_gif_attach(ifp);
562183550Szec			}
563183550Szec			CURVNET_RESTORE();
56483998Sbrooks		}
565108172Shsu		IFNET_RUNLOCK();
566196481Srwatson		VNET_LIST_RUNLOCK();
56783998Sbrooks		break;
56883998Sbrooks
56983998Sbrooks	case MOD_UNLOAD:
57083998Sbrooks
57183998Sbrooks		/*
57283998Sbrooks		 * Note that the base code won't try to unload us until
57383998Sbrooks		 * all nodes have been removed, and that can't happen
57483998Sbrooks		 * until all gif interfaces are destroyed. In any
57583998Sbrooks		 * case, we know there are no nodes left if the action
57683998Sbrooks		 * is MOD_UNLOAD, so there's no need to detach any nodes.
57783998Sbrooks		 *
57883998Sbrooks		 * XXX: what about manual unloads?!?
57983998Sbrooks		 */
58083998Sbrooks
58183998Sbrooks		/* Unregister function hooks */
58283998Sbrooks		ng_gif_attach_p = NULL;
58383998Sbrooks		ng_gif_detach_p = NULL;
58483998Sbrooks		ng_gif_input_p = NULL;
58583998Sbrooks		ng_gif_input_orphan_p = NULL;
58683998Sbrooks		break;
58783998Sbrooks
58883998Sbrooks	default:
58983998Sbrooks		error = EOPNOTSUPP;
59083998Sbrooks		break;
59183998Sbrooks	}
59283998Sbrooks	return (error);
59383998Sbrooks}
59483998Sbrooks
595