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