172909Sjulian/*-
272909Sjulian *
372909Sjulian * Copyright (c) 1999-2000, Vitaly V Belekhov
472909Sjulian * All rights reserved.
572909Sjulian *
672909Sjulian * Redistribution and use in source and binary forms, with or without
772909Sjulian * modification, are permitted provided that the following conditions
872909Sjulian * are met:
972909Sjulian * 1. Redistributions of source code must retain the above copyright
1072909Sjulian *    notice unmodified, this list of conditions, and the following
1172909Sjulian *    disclaimer.
1272909Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1372909Sjulian *    notice, this list of conditions and the following disclaimer in the
1472909Sjulian *    documentation and/or other materials provided with the distribution.
1572909Sjulian *
1672909Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1772909Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1872909Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1972909Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2072909Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2172909Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2272909Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2372909Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2472909Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2572909Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2672909Sjulian * SUCH DAMAGE.
2772909Sjulian *
2880304Sbrooks * $FreeBSD$
2972909Sjulian *
3072909Sjulian */
3172909Sjulian
3272909Sjulian#include <sys/param.h>
3372909Sjulian#include <sys/systm.h>
3472909Sjulian#include <sys/errno.h>
3572909Sjulian#include <sys/kernel.h>
3672909Sjulian#include <sys/malloc.h>
3772909Sjulian#include <sys/mbuf.h>
3872909Sjulian#include <sys/errno.h>
3972909Sjulian#include <sys/sockio.h>
4072909Sjulian#include <sys/socket.h>
4172909Sjulian#include <sys/syslog.h>
4272909Sjulian
4372909Sjulian#include <netgraph/ng_message.h>
4472909Sjulian#include <netgraph/netgraph.h>
4572909Sjulian#include <netgraph/ng_split.h>
4672909Sjulian
4772909Sjulian/* Netgraph methods */
4872909Sjulianstatic ng_constructor_t ng_split_constructor;
4980304Sbrooksstatic ng_shutdown_t ng_split_shutdown;
5072909Sjulianstatic ng_newhook_t ng_split_newhook;
5172909Sjulianstatic ng_rcvdata_t ng_split_rcvdata;
5272909Sjulianstatic ng_disconnect_t ng_split_disconnect;
5372909Sjulian
5472909Sjulian/* Node type descriptor */
5572909Sjulianstatic struct ng_type typestruct = {
56129823Sjulian	.version =	NG_ABI_VERSION,
57129823Sjulian	.name =		NG_SPLIT_NODE_TYPE,
58129823Sjulian	.constructor =	ng_split_constructor,
59129823Sjulian	.shutdown =	ng_split_shutdown,
60129823Sjulian	.newhook =	ng_split_newhook,
61129823Sjulian	.rcvdata =	ng_split_rcvdata,
62129823Sjulian	.disconnect =	ng_split_disconnect,
6372909Sjulian};
6472909SjulianNETGRAPH_INIT(ng_split, &typestruct);
6572909Sjulian
6672909Sjulian/* Node private data */
6772909Sjulianstruct ng_split_private {
6880304Sbrooks	hook_p out;
6980304Sbrooks	hook_p in;
7080304Sbrooks	hook_p mixed;
7172909Sjulian	node_p	node;			/* Our netgraph node */
7272909Sjulian};
7372909Sjuliantypedef struct ng_split_private *priv_p;
7472909Sjulian
7572909Sjulian/************************************************************************
7672909Sjulian			NETGRAPH NODE STUFF
7772909Sjulian ************************************************************************/
7872909Sjulian
7972909Sjulian/*
8072909Sjulian * Constructor for a node
8172909Sjulian */
8272909Sjulianstatic int
8372909Sjulianng_split_constructor(node_p node)
8472909Sjulian{
8580304Sbrooks	priv_p		priv;
8672909Sjulian
8772909Sjulian	/* Allocate node */
88220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH, M_ZERO | M_WAITOK);
8972909Sjulian
9072909Sjulian	/* Link together node and private info */
9172909Sjulian	NG_NODE_SET_PRIVATE(node, priv);
9272909Sjulian	priv->node = node;
9372909Sjulian
9472909Sjulian	/* Done */
9572909Sjulian	return (0);
9672909Sjulian}
9772909Sjulian
9872909Sjulian/*
9972909Sjulian * Give our ok for a hook to be added
10072909Sjulian */
10172909Sjulianstatic int
10272909Sjulianng_split_newhook(node_p node, hook_p hook, const char *name)
10372909Sjulian{
10480304Sbrooks	priv_p		priv = NG_NODE_PRIVATE(node);
10580304Sbrooks	hook_p		*localhook;
10672909Sjulian
10780304Sbrooks	if (strcmp(name, NG_SPLIT_HOOK_MIXED) == 0) {
10880304Sbrooks		localhook = &priv->mixed;
10980304Sbrooks	} else if (strcmp(name, NG_SPLIT_HOOK_IN) == 0) {
11080304Sbrooks		localhook = &priv->in;
11180304Sbrooks	} else if (strcmp(name, NG_SPLIT_HOOK_OUT) == 0) {
11280304Sbrooks		localhook = &priv->out;
113146544Sglebius	} else
114146544Sglebius		return (EINVAL);
11572909Sjulian
11680304Sbrooks	if (*localhook != NULL)
11780304Sbrooks		return (EISCONN);
11880304Sbrooks	*localhook = hook;
11980304Sbrooks	NG_HOOK_SET_PRIVATE(hook, localhook);
12080304Sbrooks
12172909Sjulian	return (0);
12272909Sjulian}
12372909Sjulian
12472909Sjulian/*
12572909Sjulian * Recive data from a hook.
12672909Sjulian */
12772909Sjulianstatic int
12872909Sjulianng_split_rcvdata(hook_p hook, item_p item)
12972909Sjulian{
13080304Sbrooks	const priv_p	priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
13180304Sbrooks	int		error = 0;
13272909Sjulian
13380304Sbrooks	if (hook == priv->out) {
13480304Sbrooks		printf("ng_split: got packet from out hook!\n");
13572909Sjulian		NG_FREE_ITEM(item);
13680304Sbrooks		error = EINVAL;
13780304Sbrooks	} else if ((hook == priv->in) && (priv->mixed != NULL)) {
13872909Sjulian		NG_FWD_ITEM_HOOK(error, item, priv->mixed);
13980304Sbrooks	} else if ((hook == priv->mixed) && (priv->out != NULL)) {
14080304Sbrooks		NG_FWD_ITEM_HOOK(error, item, priv->out);
14172909Sjulian	}
14280304Sbrooks
143149577Sglebius	if (item)
144149577Sglebius		NG_FREE_ITEM(item);
145149577Sglebius
14672909Sjulian	return (error);
14772909Sjulian}
14872909Sjulian
14972909Sjulianstatic int
15080304Sbrooksng_split_shutdown(node_p node)
15172909Sjulian{
15280304Sbrooks	const priv_p	priv = NG_NODE_PRIVATE(node);
15372909Sjulian
15472909Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
15572909Sjulian	NG_NODE_UNREF(node);
156184205Sdes	free(priv, M_NETGRAPH);
15772909Sjulian
15872909Sjulian	return (0);
15972909Sjulian}
16072909Sjulian
16172909Sjulian/*
16272909Sjulian * Hook disconnection
16372909Sjulian */
16472909Sjulianstatic int
16572909Sjulianng_split_disconnect(hook_p hook)
16672909Sjulian{
16780304Sbrooks	hook_p		*localhook = NG_HOOK_PRIVATE(hook);
16880304Sbrooks
16987599Sobrien	KASSERT(localhook != NULL, ("%s: null info", __func__));
17080304Sbrooks	*localhook = NULL;
17172909Sjulian	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
17280304Sbrooks	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
17380304Sbrooks		ng_rmnode_self(NG_HOOK_NODE(hook));
17472909Sjulian	}
17572909Sjulian
17672909Sjulian	return (0);
17772909Sjulian}
178