1128355Sru/*-
2128355Sru * Copyright (c) 2004 Ruslan Ermilov
3128355Sru * All rights reserved.
4128355Sru *
5128355Sru * Redistribution and use in source and binary forms, with or without
6128355Sru * modification, are permitted provided that the following conditions
7128355Sru * are met:
8128355Sru * 1. Redistributions of source code must retain the above copyright
9128355Sru *    notice, this list of conditions and the following disclaimer.
10128355Sru * 2. Redistributions in binary form must reproduce the above copyright
11128355Sru *    notice, this list of conditions and the following disclaimer in the
12128355Sru *    documentation and/or other materials provided with the distribution.
13128355Sru *
14128355Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15128355Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16128355Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17128355Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18128355Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19128355Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20128355Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21128355Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22128355Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23128355Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24128355Sru * SUCH DAMAGE.
25128355Sru *
26128355Sru * $FreeBSD$
27128355Sru */
28128355Sru
29128355Sru#include <sys/param.h>
30128355Sru#include <sys/errno.h>
31128355Sru#include <sys/kernel.h>
32128355Sru#include <sys/mbuf.h>
33128355Sru#include <sys/systm.h>
34128355Sru
35128355Sru#include <netgraph/ng_message.h>
36128355Sru#include <netgraph/ng_hub.h>
37128355Sru#include <netgraph/netgraph.h>
38128355Sru
39207680Szec#ifdef NG_SEPARATE_MALLOC
40227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_HUB, "netgraph_hub", "netgraph hub node");
41207680Szec#else
42207680Szec#define M_NETGRAPH_HUB M_NETGRAPH
43207680Szec#endif
44207680Szec
45207680Szec/* Per-node private data */
46207680Szecstruct ng_hub_private {
47207680Szec	int		persistent;	/* can exist w/o hooks */
48207680Szec};
49207680Szectypedef struct ng_hub_private *priv_p;
50207680Szec
51207680Szec/* Netgraph node methods */
52128355Srustatic ng_constructor_t	ng_hub_constructor;
53207680Szecstatic ng_rcvmsg_t	ng_hub_rcvmsg;
54207680Szecstatic ng_shutdown_t	ng_hub_shutdown;
55128355Srustatic ng_rcvdata_t	ng_hub_rcvdata;
56128355Srustatic ng_disconnect_t	ng_hub_disconnect;
57128355Sru
58207680Szec/* List of commands and how to convert arguments to/from ASCII */
59207680Szecstatic const struct ng_cmdlist ng_hub_cmdlist[] = {
60207680Szec	{
61207680Szec		NGM_HUB_COOKIE,
62207680Szec		NGM_HUB_SET_PERSISTENT,
63207680Szec		"setpersistent",
64207680Szec		NULL,
65207680Szec		NULL
66207680Szec	},
67207680Szec	{ 0 }
68207680Szec};
69207680Szec
70128355Srustatic struct ng_type ng_hub_typestruct = {
71128355Sru	.version =	NG_ABI_VERSION,
72128355Sru	.name =		NG_HUB_NODE_TYPE,
73128355Sru	.constructor =	ng_hub_constructor,
74207680Szec	.rcvmsg =	ng_hub_rcvmsg,
75207680Szec	.shutdown =	ng_hub_shutdown,
76128355Sru	.rcvdata =	ng_hub_rcvdata,
77128355Sru	.disconnect =	ng_hub_disconnect,
78207680Szec	.cmdlist =	ng_hub_cmdlist,
79128355Sru};
80128355SruNETGRAPH_INIT(hub, &ng_hub_typestruct);
81128355Sru
82128355Sru
83128355Srustatic int
84128355Srung_hub_constructor(node_p node)
85128355Sru{
86207680Szec	priv_p priv;
87128355Sru
88207680Szec	/* Allocate and initialize private info */
89220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_HUB, M_WAITOK | M_ZERO);
90207680Szec
91207680Szec	NG_NODE_SET_PRIVATE(node, priv);
92128355Sru	return (0);
93128355Sru}
94128355Sru
95207680Szec/*
96207680Szec * Receive a control message
97207680Szec */
98128355Srustatic int
99207680Szecng_hub_rcvmsg(node_p node, item_p item, hook_p lasthook)
100207680Szec{
101207680Szec	const priv_p priv = NG_NODE_PRIVATE(node);
102207680Szec	int error = 0;
103207680Szec	struct ng_mesg *msg;
104207680Szec
105207680Szec	NGI_GET_MSG(item, msg);
106207680Szec	if (msg->header.typecookie == NGM_HUB_COOKIE &&
107207680Szec	    msg->header.cmd == NGM_HUB_SET_PERSISTENT) {
108207680Szec		priv->persistent = 1;
109207680Szec	} else {
110207680Szec		error = EINVAL;
111207680Szec	}
112207680Szec
113207680Szec	NG_FREE_MSG(msg);
114207680Szec	return (error);
115207680Szec}
116207680Szec
117207680Szecstatic int
118128355Srung_hub_rcvdata(hook_p hook, item_p item)
119128355Sru{
120128355Sru	const node_p node = NG_HOOK_NODE(hook);
121128355Sru	int error = 0;
122128355Sru	hook_p hook2;
123128355Sru	struct mbuf * const m = NGI_M(item), *m2;
124128355Sru	int nhooks;
125128355Sru
126128355Sru	if ((nhooks = NG_NODE_NUMHOOKS(node)) == 1) {
127128355Sru		NG_FREE_ITEM(item);
128128355Sru		return (0);
129128355Sru	}
130128355Sru	LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
131128355Sru		if (hook2 == hook)
132128355Sru			continue;
133128355Sru		if (--nhooks == 1)
134128355Sru			NG_FWD_ITEM_HOOK(error, item, hook2);
135128355Sru		else {
136243882Sglebius			if ((m2 = m_dup(m, M_NOWAIT)) == NULL) {
137128355Sru				NG_FREE_ITEM(item);
138128355Sru				return (ENOBUFS);
139128355Sru			}
140131155Sjulian			NG_SEND_DATA_ONLY(error, hook2, m2);
141128355Sru			if (error)
142128371Sru				continue;	/* don't give up */
143128355Sru		}
144128355Sru	}
145128355Sru
146128355Sru	return (error);
147128355Sru}
148128355Sru
149207680Szec/*
150207680Szec * Shutdown node
151207680Szec */
152128355Srustatic int
153207680Szecng_hub_shutdown(node_p node)
154207680Szec{
155207680Szec	const priv_p priv = NG_NODE_PRIVATE(node);
156207680Szec
157207680Szec	free(priv, M_NETGRAPH_HUB);
158220416Szec	NG_NODE_SET_PRIVATE(node, NULL);
159220416Szec	NG_NODE_UNREF(node);
160207680Szec	return (0);
161207680Szec}
162207680Szec
163207680Szecstatic int
164128355Srung_hub_disconnect(hook_p hook)
165128355Sru{
166207680Szec	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
167128355Sru
168128355Sru	if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
169207680Szec	    NG_NODE_IS_VALID(NG_HOOK_NODE(hook)) && !priv->persistent)
170128355Sru		ng_rmnode_self(NG_HOOK_NODE(hook));
171128355Sru	return (0);
172128355Sru}
173