183998Sbrooks/*
283998Sbrooks * ng_gif_demux.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-1999 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_demux(4) netgraph node type
7083998Sbrooks *
7183998Sbrooks * Packets received on the "gif" hook have their type header removed
7283998Sbrooks * and are passed to the appropriate hook protocol hook.  Packets
7383998Sbrooks * recieved on a protocol hook have a type header added back and are
7483998Sbrooks * passed out the gif hook. The currently supported protocol hooks are:
7583998Sbrooks */
7683998Sbrooks
7783998Sbrooks#include <sys/param.h>
7883998Sbrooks#include <sys/systm.h>
7983998Sbrooks#include <sys/kernel.h>
8083998Sbrooks#include <sys/malloc.h>
8183998Sbrooks#include <sys/ctype.h>
8283998Sbrooks#include <sys/mbuf.h>
8383998Sbrooks#include <sys/errno.h>
8483998Sbrooks#include <sys/socket.h>
8583998Sbrooks
8683998Sbrooks#include <netgraph/ng_message.h>
8783998Sbrooks#include <netgraph/netgraph.h>
8883998Sbrooks#include <netgraph/ng_parse.h>
8983998Sbrooks#include <netgraph/ng_gif_demux.h>
9083998Sbrooks
9183998Sbrooks#ifdef NG_SEPARATE_MALLOC
92227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_GIF_DEMUX, "netgraph_gif_demux",
9383998Sbrooks    "netgraph gif demux node");
9483998Sbrooks#else
9583998Sbrooks#define M_NETGRAPH_GIF_DEMUX M_NETGRAPH
9683998Sbrooks#endif
9783998Sbrooks
9883998Sbrooks/* This struct describes one address family */
9983998Sbrooksstruct iffam {
10083998Sbrooks	sa_family_t	family;		/* Address family */
10183998Sbrooks	const char	*hookname;	/* Name for hook */
10283998Sbrooks};
10383998Sbrookstypedef const struct iffam *iffam_p;
10483998Sbrooks
10583998Sbrooks/* List of address families supported by our interface */
10683998Sbrooksconst static struct iffam gFamilies[] = {
10783998Sbrooks	{ AF_INET,	NG_GIF_DEMUX_HOOK_INET	},
10883998Sbrooks	{ AF_INET6,	NG_GIF_DEMUX_HOOK_INET6	},
10983998Sbrooks	{ AF_APPLETALK,	NG_GIF_DEMUX_HOOK_ATALK	},
11083998Sbrooks	{ AF_IPX,	NG_GIF_DEMUX_HOOK_IPX	},
11183998Sbrooks	{ AF_ATM,	NG_GIF_DEMUX_HOOK_ATM	},
11283998Sbrooks	{ AF_NATM,	NG_GIF_DEMUX_HOOK_NATM	},
11383998Sbrooks};
11483998Sbrooks#define NUM_FAMILIES		(sizeof(gFamilies) / sizeof(*gFamilies))
11583998Sbrooks
11683998Sbrooks/* Per-node private data */
11783998Sbrooksstruct ng_gif_demux_private {
11883998Sbrooks	node_p	node;			/* Our netgraph node */
11983998Sbrooks	hook_p	gif;			/* The gif hook */
12083998Sbrooks	hook_p	hooks[NUM_FAMILIES];	/* The protocol hooks */
12183998Sbrooks};
12283998Sbrookstypedef struct ng_gif_demux_private *priv_p;
12383998Sbrooks
12483998Sbrooks/* Netgraph node methods */
12583998Sbrooksstatic ng_constructor_t	ng_gif_demux_constructor;
12683998Sbrooksstatic ng_rcvmsg_t	ng_gif_demux_rcvmsg;
12783998Sbrooksstatic ng_shutdown_t	ng_gif_demux_shutdown;
12883998Sbrooksstatic ng_newhook_t	ng_gif_demux_newhook;
12983998Sbrooksstatic ng_rcvdata_t	ng_gif_demux_rcvdata;
13083998Sbrooksstatic ng_disconnect_t	ng_gif_demux_disconnect;
13183998Sbrooks
13283998Sbrooks/* Helper stuff */
13383998Sbrooksstatic iffam_p	get_iffam_from_af(sa_family_t family);
13483998Sbrooksstatic iffam_p	get_iffam_from_hook(priv_p priv, hook_p hook);
13583998Sbrooksstatic iffam_p	get_iffam_from_name(const char *name);
13683998Sbrooksstatic hook_p	*get_hook_from_iffam(priv_p priv, iffam_p iffam);
13783998Sbrooks
13883998Sbrooks/******************************************************************
13983998Sbrooks		    NETGRAPH PARSE TYPES
14083998Sbrooks******************************************************************/
14183998Sbrooks
14283998Sbrooks/* List of commands and how to convert arguments to/from ASCII */
14383998Sbrooksstatic const struct ng_cmdlist ng_gif_demux_cmdlist[] = {
14483998Sbrooks	{ 0 }
14583998Sbrooks};
14683998Sbrooks
14783998Sbrooks/* Node type descriptor */
14883998Sbrooksstatic struct ng_type ng_gif_demux_typestruct = {
149129823Sjulian	.version =	NG_ABI_VERSION,
150129823Sjulian	.name =		NG_GIF_DEMUX_NODE_TYPE,
151129823Sjulian	.constructor =	ng_gif_demux_constructor,
152129823Sjulian	.rcvmsg =	ng_gif_demux_rcvmsg,
153129823Sjulian	.shutdown =	ng_gif_demux_shutdown,
154129823Sjulian	.newhook =	ng_gif_demux_newhook,
155129823Sjulian	.rcvdata =	ng_gif_demux_rcvdata,
156129823Sjulian	.disconnect =	ng_gif_demux_disconnect,
157129823Sjulian	.cmdlist =	ng_gif_demux_cmdlist,
15883998Sbrooks};
15983998SbrooksNETGRAPH_INIT(gif_demux, &ng_gif_demux_typestruct);
16083998Sbrooks
16183998Sbrooks/************************************************************************
16283998Sbrooks		    HELPER STUFF
16383998Sbrooks ************************************************************************/
16483998Sbrooks
16583998Sbrooks/*
16683998Sbrooks * Get the family descriptor from the family ID
16783998Sbrooks */
168131575Sstefanfstatic __inline iffam_p
16983998Sbrooksget_iffam_from_af(sa_family_t family)
17083998Sbrooks{
17183998Sbrooks	iffam_p iffam;
17283998Sbrooks	int k;
17383998Sbrooks
17483998Sbrooks	for (k = 0; k < NUM_FAMILIES; k++) {
17583998Sbrooks		iffam = &gFamilies[k];
17683998Sbrooks		if (iffam->family == family)
17783998Sbrooks			return (iffam);
17883998Sbrooks	}
17983998Sbrooks	return (NULL);
18083998Sbrooks}
18183998Sbrooks
18283998Sbrooks/*
18383998Sbrooks * Get the family descriptor from the hook
18483998Sbrooks */
185131575Sstefanfstatic __inline iffam_p
18683998Sbrooksget_iffam_from_hook(priv_p priv, hook_p hook)
18783998Sbrooks{
18883998Sbrooks	int k;
18983998Sbrooks
19083998Sbrooks	for (k = 0; k < NUM_FAMILIES; k++)
19183998Sbrooks		if (priv->hooks[k] == hook)
19283998Sbrooks			return (&gFamilies[k]);
19383998Sbrooks	return (NULL);
19483998Sbrooks}
19583998Sbrooks
19683998Sbrooks/*
19783998Sbrooks * Get the hook from the iffam descriptor
19883998Sbrooks */
19983998Sbrooks
200131575Sstefanfstatic __inline hook_p *
20183998Sbrooksget_hook_from_iffam(priv_p priv, iffam_p iffam)
20283998Sbrooks{
20383998Sbrooks	return (&priv->hooks[iffam - gFamilies]);
20483998Sbrooks}
20583998Sbrooks
20683998Sbrooks/*
20783998Sbrooks * Get the iffam descriptor from the name
20883998Sbrooks */
209131575Sstefanfstatic __inline iffam_p
21083998Sbrooksget_iffam_from_name(const char *name)
21183998Sbrooks{
21283998Sbrooks	iffam_p iffam;
21383998Sbrooks	int k;
21483998Sbrooks
21583998Sbrooks	for (k = 0; k < NUM_FAMILIES; k++) {
21683998Sbrooks		iffam = &gFamilies[k];
21783998Sbrooks		if (!strcmp(iffam->hookname, name))
21883998Sbrooks			return (iffam);
21983998Sbrooks	}
22083998Sbrooks	return (NULL);
22183998Sbrooks}
22283998Sbrooks
22383998Sbrooks/******************************************************************
22483998Sbrooks		    NETGRAPH NODE METHODS
22583998Sbrooks******************************************************************/
22683998Sbrooks
22783998Sbrooks/*
22883998Sbrooks * Node constructor
22983998Sbrooks */
23083998Sbrooksstatic int
23183998Sbrooksng_gif_demux_constructor(node_p node)
23283998Sbrooks{
23383998Sbrooks	priv_p priv;
23483998Sbrooks
23583998Sbrooks	/* Allocate and initialize private info */
236220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_GIF_DEMUX, M_WAITOK | M_ZERO);
23783998Sbrooks	priv->node = node;
23883998Sbrooks
23983998Sbrooks	NG_NODE_SET_PRIVATE(node, priv);
24083998Sbrooks
24183998Sbrooks	/* Done */
24283998Sbrooks	return (0);
24383998Sbrooks}
24483998Sbrooks
24583998Sbrooks/*
24683998Sbrooks * Method for attaching a new hook
24783998Sbrooks */
24883998Sbrooksstatic	int
24983998Sbrooksng_gif_demux_newhook(node_p node, hook_p hook, const char *name)
25083998Sbrooks{
25183998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
25283998Sbrooks	iffam_p iffam;
25383998Sbrooks	hook_p *hookptr;
25483998Sbrooks
25583998Sbrooks	if (strcmp(NG_GIF_DEMUX_HOOK_GIF, name) == 0)
25683998Sbrooks		hookptr = &priv->gif;
25783998Sbrooks	else {
25883998Sbrooks		iffam = get_iffam_from_name(name);
25983998Sbrooks		if (iffam == NULL)
26083998Sbrooks			return (EPFNOSUPPORT);
26183998Sbrooks		hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam);
26283998Sbrooks	}
26383998Sbrooks	if (*hookptr != NULL)
26483998Sbrooks		return (EISCONN);
26583998Sbrooks	*hookptr = hook;
26683998Sbrooks	return (0);
26783998Sbrooks}
26883998Sbrooks
26983998Sbrooks/*
27083998Sbrooks * Receive a control message
27183998Sbrooks */
27283998Sbrooksstatic int
27383998Sbrooksng_gif_demux_rcvmsg(node_p node, item_p item, hook_p lasthook)
27483998Sbrooks{
27583998Sbrooks	struct ng_mesg *resp = NULL;
27683998Sbrooks	int error = 0;
27783998Sbrooks	struct ng_mesg *msg;
27883998Sbrooks
27983998Sbrooks	NGI_GET_MSG(item, msg);
28083998Sbrooks	switch (msg->header.typecookie) {
28183998Sbrooks	case NGM_GIF_DEMUX_COOKIE:
28283998Sbrooks		switch (msg->header.cmd) {
28383998Sbrooks		/* XXX: Add commands here. */
28483998Sbrooks		default:
28583998Sbrooks			error = EINVAL;
28683998Sbrooks			break;
28783998Sbrooks		}
28883998Sbrooks		break;
28983998Sbrooks	default:
29083998Sbrooks		error = EINVAL;
29183998Sbrooks		break;
29283998Sbrooks	}
29383998Sbrooks
29483998Sbrooks	/* Done */
29583998Sbrooks	NG_RESPOND_MSG(error, node, item, resp);
29683998Sbrooks	NG_FREE_MSG(msg);
29783998Sbrooks	return (error);
29883998Sbrooks}
29983998Sbrooks
30083998Sbrooks/*
30183998Sbrooks * Receive data on a hook
30283998Sbrooks */
30383998Sbrooksstatic int
30483998Sbrooksng_gif_demux_rcvdata(hook_p hook, item_p item)
30583998Sbrooks{
30683998Sbrooks	const node_p node = NG_HOOK_NODE(hook);
30783998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
30883998Sbrooks	iffam_p iffam;
30983998Sbrooks	hook_p outhook;
31083998Sbrooks	int error = 0;
31183998Sbrooks	struct mbuf *m;
31283998Sbrooks
31383998Sbrooks	/* Pull the mbuf out of the item for processing. */
31483998Sbrooks	NGI_GET_M(item, m);
31583998Sbrooks
31683998Sbrooks	if (hook == priv->gif) {
31783998Sbrooks		/*
31883998Sbrooks		 * Pull off the address family header and find the
31983998Sbrooks		 * output hook.
32083998Sbrooks		 */
32183998Sbrooks		if (m->m_pkthdr.len < sizeof(sa_family_t)) {
32283998Sbrooks			NG_FREE_M(m);
32383998Sbrooks			NG_FREE_ITEM(item);
32483998Sbrooks			return (EINVAL);
32583998Sbrooks		}
32683998Sbrooks		if (m->m_len < sizeof(sa_family_t)
32783998Sbrooks		    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
32883998Sbrooks			NG_FREE_ITEM(item);
32983998Sbrooks			return (ENOBUFS);
33083998Sbrooks		}
33183998Sbrooks		iffam = get_iffam_from_af(*mtod(m, sa_family_t *));
33283998Sbrooks		if (iffam == NULL) {
33383998Sbrooks			NG_FREE_M(m);
33483998Sbrooks			NG_FREE_ITEM(item);
33583998Sbrooks			return (EINVAL);
33683998Sbrooks		}
33783998Sbrooks		outhook = *get_hook_from_iffam(priv, iffam);
33883998Sbrooks		m_adj(m, sizeof(sa_family_t));
33983998Sbrooks	} else {
34083998Sbrooks		/*
34183998Sbrooks		 * Add address family header and set the output hook.
34283998Sbrooks		 */
34383998Sbrooks		iffam = get_iffam_from_hook(priv, hook);
344243882Sglebius		M_PREPEND(m, sizeof (iffam->family), M_NOWAIT);
34583998Sbrooks		if (m == NULL) {
34683998Sbrooks			NG_FREE_M(m);
34783998Sbrooks			NG_FREE_ITEM(item);
34883998Sbrooks			return (ENOBUFS);
34983998Sbrooks		}
35083998Sbrooks		bcopy(&iffam->family, mtod(m, sa_family_t *),
35183998Sbrooks		    sizeof(iffam->family));
35283998Sbrooks		outhook = priv->gif;
35383998Sbrooks	}
35483998Sbrooks
35583998Sbrooks	/* Stuff the mbuf back in. */
35683998Sbrooks	NGI_M(item) = m;
35783998Sbrooks
35883998Sbrooks	/* Deliver packet */
35983998Sbrooks	NG_FWD_ITEM_HOOK(error, item, outhook);
36083998Sbrooks	return (error);
36183998Sbrooks}
36283998Sbrooks
36383998Sbrooks/*
36483998Sbrooks * Shutdown node
36583998Sbrooks */
36683998Sbrooksstatic int
36783998Sbrooksng_gif_demux_shutdown(node_p node)
36883998Sbrooks{
36983998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(node);
37083998Sbrooks
371184205Sdes	free(priv, M_NETGRAPH_GIF_DEMUX);
37283998Sbrooks	NG_NODE_SET_PRIVATE(node, NULL);
37383998Sbrooks	NG_NODE_UNREF(node);
37483998Sbrooks	return (0);
37583998Sbrooks}
37683998Sbrooks
37783998Sbrooks/*
37883998Sbrooks * Hook disconnection.
37983998Sbrooks */
38083998Sbrooksstatic int
38183998Sbrooksng_gif_demux_disconnect(hook_p hook)
38283998Sbrooks{
38383998Sbrooks	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
38483998Sbrooks	iffam_p iffam;
38583998Sbrooks
38683998Sbrooks	if (hook == priv->gif)
38783998Sbrooks		priv->gif = NULL;
38883998Sbrooks	else {
38983998Sbrooks		iffam = get_iffam_from_hook(priv, hook);
39083998Sbrooks		if (iffam == NULL)
391213794Srpaulo			panic("%s", __func__);
39283998Sbrooks		*get_hook_from_iffam(priv, iffam) = NULL;
39383998Sbrooks	}
39483998Sbrooks
39583998Sbrooks	return (0);
39683998Sbrooks}
397