xref: /freebsd/sys/netgraph/ng_tee.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 
2 /*
3  * ng_tee.c
4  *
5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6  * All rights reserved.
7  *
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  *
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Julian Elischer <julian@whistle.com>
38  *
39  * $FreeBSD$
40  * $Whistle: ng_tee.c,v 1.16 1999/01/28 23:54:54 julian Exp $
41  */
42 
43 /*
44  * This node is like the tee(1) command and is useful for ``snooping.''
45  * It has 4 hooks: left, right, left2right, and right2left. Data
46  * entering from the right is passed to the left and duplicated on
47  * right2left, and data entering from the left is passed to the right
48  * and duplicated on left2right. Data entering from left2right is
49  * sent to right, and data from right2left to left.
50  */
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/errno.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/mbuf.h>
58 #include <netgraph/ng_message.h>
59 #include <netgraph/netgraph.h>
60 #include <netgraph/ng_tee.h>
61 
62 /* Per hook info */
63 struct hookinfo {
64 	hook_p  hook;
65 	int     bytes;
66 	int     packets;
67 	int     flags;
68 };
69 
70 /* Per node info */
71 struct privdata {
72 	node_p  node;
73 	int     flags;
74 	struct hookinfo left;
75 	struct hookinfo right;
76 	struct hookinfo left2right;
77 	struct hookinfo right2left;
78 };
79 typedef struct privdata *sc_p;
80 
81 /* Netgraph methods */
82 static int	ngt_constructor(node_p *node);
83 static int	ngt_rcvmsg(node_p node, struct ng_mesg *msg,
84 		    const char *retaddr, struct ng_mesg **resp);
85 static int	ngt_rmnode(node_p node);
86 static int	ngt_newhook(node_p node, hook_p hook, const char *name);
87 static int	ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
88 static int	ngt_disconnect(hook_p hook);
89 
90 /* Netgraph type descriptor */
91 static struct ng_type typestruct = {
92 	NG_VERSION,
93 	NG_TEE_NODE_TYPE,
94 	NULL,
95 	ngt_constructor,
96 	ngt_rcvmsg,
97 	ngt_rmnode,
98 	ngt_newhook,
99 	NULL,
100 	NULL,
101 	ngt_rcvdata,
102 	ngt_rcvdata,
103 	ngt_disconnect
104 };
105 NETGRAPH_INIT(tee, &typestruct);
106 
107 /*
108  * Node constructor
109  */
110 static int
111 ngt_constructor(node_p *nodep)
112 {
113 	sc_p privdata;
114 	int error = 0;
115 
116 	MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK);
117 	if (privdata == NULL)
118 		return (ENOMEM);
119 	bzero(privdata, sizeof(*privdata));
120 
121 	if ((error = ng_make_node_common(&typestruct, nodep))) {
122 		FREE(privdata, M_NETGRAPH);
123 		return (error);
124 	}
125 	(*nodep)->private = privdata;
126 	privdata->node = *nodep;
127 	return (0);
128 }
129 
130 /*
131  * Add a hook
132  */
133 static int
134 ngt_newhook(node_p node, hook_p hook, const char *name)
135 {
136 	const sc_p sc = node->private;
137 
138 	if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) {
139 		sc->right.hook = hook;
140 		sc->right.bytes = 0;
141 		sc->right.packets = 0;
142 		hook->private = &sc->right;
143 	} else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) {
144 		sc->left.hook = hook;
145 		sc->left.bytes = 0;
146 		sc->left.packets = 0;
147 		hook->private = &sc->left;
148 	} else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) {
149 		sc->right2left.hook = hook;
150 		sc->right2left.bytes = 0;
151 		sc->right2left.packets = 0;
152 		hook->private = &sc->right2left;
153 	} else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) {
154 		sc->left2right.hook = hook;
155 		sc->left2right.bytes = 0;
156 		sc->left2right.packets = 0;
157 		hook->private = &sc->left2right;
158 	} else
159 		return (EINVAL);
160 	return (0);
161 }
162 
163 /*
164  * We don't support any type-specific messages
165  */
166 static int
167 ngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
168 	   struct ng_mesg **resp)
169 {
170 	FREE(msg, M_NETGRAPH);
171 	return (EINVAL);
172 }
173 
174 /*
175  * Receive data on a hook
176  *
177  * If data comes in the right link send a copy out right2left, and then
178  * send the original onwards out through the left link.
179  * Do the opposite for data coming in from the left link.
180  * Data coming in right2left or left2right is forwarded
181  * on through the appropriate destination hook as if it had come
182  * from the other side.
183  */
184 static int
185 ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
186 {
187 	const sc_p sc = hook->node->private;
188 	struct hookinfo *hi;
189 	struct hookinfo *dest;
190 	struct hookinfo *dup;
191 	struct mbuf *mdup;
192 	int error = 0;
193 
194 	if ((hi = hook->private) != NULL) {
195 		if (hi == &sc->left) {
196 			dup = &sc->left2right;
197 			dest = &sc->right;
198 		} else if (hi == &sc->right) {
199 			dup = &sc->right2left;
200 			dest = &sc->left;
201 		} else if (hi == &sc->right2left) {
202 			dup = NULL;
203 			dest = &sc->left;
204 		} else if (hi == &sc->left2right) {
205 			dup = NULL;
206 			dest = &sc->right;
207 		} else
208 			goto out;
209 		if (dup) {
210 			mdup = m_copypacket(m, M_NOWAIT);
211 			if (mdup) {
212 				/* XXX should we duplicate meta? */
213 				/* for now no.			 */
214 				void   *x = NULL;
215 
216 				NG_SEND_DATA(error, dup->hook, mdup, x);
217 			}
218 		}
219 		NG_SEND_DATA(error, dest->hook, m, meta);
220 	}
221 
222 out:
223 	NG_FREE_DATA(m, meta);
224 	return (error);
225 }
226 
227 /*
228  * Shutdown processing
229  *
230  * This is tricky. If we have both a left and right hook, then we
231  * probably want to extricate ourselves and leave the two peers
232  * still linked to each other. Otherwise we should just shut down as
233  * a normal node would.
234  *
235  * To keep the scope of info correct the routine to "extract" a node
236  * from two links is in ng_base.c.
237  */
238 static int
239 ngt_rmnode(node_p node)
240 {
241 	const sc_p privdata = node->private;
242 
243 	node->flags |= NG_INVALID;
244 	if (privdata->left.hook && privdata->right.hook)
245 		ng_bypass(privdata->left.hook, privdata->right.hook);
246 	ng_cutlinks(node);
247 	ng_unname(node);
248 	node->private = NULL;
249 	ng_unref(privdata->node);
250 	FREE(privdata, M_NETGRAPH);
251 	return (0);
252 }
253 
254 /*
255  * Hook disconnection
256  */
257 static int
258 ngt_disconnect(hook_p hook)
259 {
260 	struct hookinfo *hi;
261 
262 	if ((hi = hook->private) != NULL)
263 		hi->hook = NULL;
264 	if (hook->node->numhooks == 0)
265 		ng_rmnode(hook->node);
266 	return (0);
267 }
268 
269