FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_tee.c
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@freebsd.org>
38 *
39 * $FreeBSD: releng/5.3/sys/netgraph/ng_tee.c 136588 2004-10-16 08:43:07Z cvs2svn $
40 * $Whistle: ng_tee.c,v 1.18 1999/11/01 09:24:52 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 left, and data from right2left to right.
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_parse.h>
61 #include <netgraph/ng_tee.h>
62
63 /* Per hook info */
64 struct hookinfo {
65 hook_p hook;
66 struct ng_tee_hookstat stats;
67 };
68
69 /* Per node info */
70 struct privdata {
71 node_p node;
72 struct hookinfo left;
73 struct hookinfo right;
74 struct hookinfo left2right;
75 struct hookinfo right2left;
76 };
77 typedef struct privdata *sc_p;
78
79 /* Netgraph methods */
80 static ng_constructor_t ngt_constructor;
81 static ng_rcvmsg_t ngt_rcvmsg;
82 static ng_close_t ngt_close;
83 static ng_shutdown_t ngt_shutdown;
84 static ng_newhook_t ngt_newhook;
85 static ng_rcvdata_t ngt_rcvdata;
86 static ng_disconnect_t ngt_disconnect;
87
88 /* Parse type for struct ng_tee_hookstat */
89 static const struct ng_parse_struct_field ng_tee_hookstat_type_fields[]
90 = NG_TEE_HOOKSTAT_INFO;
91 static const struct ng_parse_type ng_tee_hookstat_type = {
92 &ng_parse_struct_type,
93 &ng_tee_hookstat_type_fields
94 };
95
96 /* Parse type for struct ng_tee_stats */
97 static const struct ng_parse_struct_field ng_tee_stats_type_fields[]
98 = NG_TEE_STATS_INFO(&ng_tee_hookstat_type);
99 static const struct ng_parse_type ng_tee_stats_type = {
100 &ng_parse_struct_type,
101 &ng_tee_stats_type_fields
102 };
103
104 /* List of commands and how to convert arguments to/from ASCII */
105 static const struct ng_cmdlist ng_tee_cmds[] = {
106 {
107 NGM_TEE_COOKIE,
108 NGM_TEE_GET_STATS,
109 "getstats",
110 NULL,
111 &ng_tee_stats_type
112 },
113 {
114 NGM_TEE_COOKIE,
115 NGM_TEE_CLR_STATS,
116 "clrstats",
117 NULL,
118 NULL
119 },
120 {
121 NGM_TEE_COOKIE,
122 NGM_TEE_GETCLR_STATS,
123 "getclrstats",
124 NULL,
125 &ng_tee_stats_type
126 },
127 { 0 }
128 };
129
130 /* Netgraph type descriptor */
131 static struct ng_type ng_tee_typestruct = {
132 .version = NG_ABI_VERSION,
133 .name = NG_TEE_NODE_TYPE,
134 .constructor = ngt_constructor,
135 .rcvmsg = ngt_rcvmsg,
136 .close = ngt_close,
137 .shutdown = ngt_shutdown,
138 .newhook = ngt_newhook,
139 .rcvdata = ngt_rcvdata,
140 .disconnect = ngt_disconnect,
141 .cmdlist = ng_tee_cmds,
142 };
143 NETGRAPH_INIT(tee, &ng_tee_typestruct);
144
145 /*
146 * Node constructor
147 */
148 static int
149 ngt_constructor(node_p node)
150 {
151 sc_p privdata;
152
153 MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_NOWAIT|M_ZERO);
154 if (privdata == NULL)
155 return (ENOMEM);
156
157 NG_NODE_SET_PRIVATE(node, privdata);
158 privdata->node = node;
159 return (0);
160 }
161
162 /*
163 * Add a hook
164 */
165 static int
166 ngt_newhook(node_p node, hook_p hook, const char *name)
167 {
168 const sc_p sc = NG_NODE_PRIVATE(node);
169
170 if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) {
171 sc->right.hook = hook;
172 bzero(&sc->right.stats, sizeof(sc->right.stats));
173 NG_HOOK_SET_PRIVATE(hook, &sc->right);
174 } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) {
175 sc->left.hook = hook;
176 bzero(&sc->left.stats, sizeof(sc->left.stats));
177 NG_HOOK_SET_PRIVATE(hook, &sc->left);
178 } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) {
179 sc->right2left.hook = hook;
180 bzero(&sc->right2left.stats, sizeof(sc->right2left.stats));
181 NG_HOOK_SET_PRIVATE(hook, &sc->right2left);
182 } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) {
183 sc->left2right.hook = hook;
184 bzero(&sc->left2right.stats, sizeof(sc->left2right.stats));
185 NG_HOOK_SET_PRIVATE(hook, &sc->left2right);
186 } else
187 return (EINVAL);
188 return (0);
189 }
190
191 /*
192 * Receive a control message
193 */
194 static int
195 ngt_rcvmsg(node_p node, item_p item, hook_p lasthook)
196 {
197 const sc_p sc = NG_NODE_PRIVATE(node);
198 struct ng_mesg *resp = NULL;
199 int error = 0;
200 struct ng_mesg *msg;
201
202 NGI_GET_MSG(item, msg);
203 switch (msg->header.typecookie) {
204 case NGM_TEE_COOKIE:
205 switch (msg->header.cmd) {
206 case NGM_TEE_GET_STATS:
207 case NGM_TEE_CLR_STATS:
208 case NGM_TEE_GETCLR_STATS:
209 {
210 struct ng_tee_stats *stats;
211
212 if (msg->header.cmd != NGM_TEE_CLR_STATS) {
213 NG_MKRESPONSE(resp, msg,
214 sizeof(*stats), M_NOWAIT);
215 if (resp == NULL) {
216 error = ENOMEM;
217 goto done;
218 }
219 stats = (struct ng_tee_stats *)resp->data;
220 bcopy(&sc->right.stats, &stats->right,
221 sizeof(stats->right));
222 bcopy(&sc->left.stats, &stats->left,
223 sizeof(stats->left));
224 bcopy(&sc->right2left.stats, &stats->right2left,
225 sizeof(stats->right2left));
226 bcopy(&sc->left2right.stats, &stats->left2right,
227 sizeof(stats->left2right));
228 }
229 if (msg->header.cmd != NGM_TEE_GET_STATS) {
230 bzero(&sc->right.stats,
231 sizeof(sc->right.stats));
232 bzero(&sc->left.stats,
233 sizeof(sc->left.stats));
234 bzero(&sc->right2left.stats,
235 sizeof(sc->right2left.stats));
236 bzero(&sc->left2right.stats,
237 sizeof(sc->left2right.stats));
238 }
239 break;
240 }
241 default:
242 error = EINVAL;
243 break;
244 }
245 break;
246 case NGM_FLOW_COOKIE:
247 if (lasthook) {
248 if (lasthook == sc->left.hook) {
249 if (sc->right.hook) {
250 NGI_MSG(item) = msg;
251 NG_FWD_ITEM_HOOK(error, item,
252 sc->right.hook);
253 return (error);
254 }
255 } else {
256 if (sc->left.hook) {
257 NGI_MSG(item) = msg;
258 NG_FWD_ITEM_HOOK(error, item,
259 sc->left.hook);
260 return (error);
261 }
262 }
263 }
264 break;
265 default:
266 error = EINVAL;
267 break;
268 }
269 done:
270 NG_RESPOND_MSG(error, node, item, resp);
271 NG_FREE_MSG(msg);
272 return (error);
273 }
274
275 /*
276 * Receive data on a hook
277 *
278 * If data comes in the right link send a copy out right2left, and then
279 * send the original onwards out through the left link.
280 * Do the opposite for data coming in from the left link.
281 * Data coming in right2left or left2right is forwarded
282 * on through the appropriate destination hook as if it had come
283 * from the other side.
284 */
285 static int
286 ngt_rcvdata(hook_p hook, item_p item)
287 {
288 const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
289 struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook);
290 struct hookinfo *dest;
291 struct hookinfo *dup;
292 int error = 0;
293 struct mbuf *m;
294
295 m = NGI_M(item);
296 /* Which hook? */
297 if (hinfo == &sc->left) {
298 dup = &sc->left2right;
299 dest = &sc->right;
300 } else if (hinfo == &sc->right) {
301 dup = &sc->right2left;
302 dest = &sc->left;
303 } else if (hinfo == &sc->right2left) {
304 dup = NULL;
305 dest = &sc->right;
306 } else if (hinfo == &sc->left2right) {
307 dup = NULL;
308 dest = &sc->left;
309 } else {
310 panic("%s: no hook!", __func__);
311 #ifdef RESTARTABLE_PANICS
312 return(EINVAL);
313 #endif
314 }
315
316 /* Update stats on incoming hook */
317 hinfo->stats.inOctets += m->m_pkthdr.len;
318 hinfo->stats.inFrames++;
319
320 /*
321 * Don't make a copy if only the dup hook exists.
322 */
323 if ((dup && dup->hook) && (dest->hook == NULL)) {
324 dest = dup;
325 dup = NULL;
326 }
327
328 /* Duplicate packet if requried */
329 if (dup && dup->hook) {
330 struct mbuf *m2;
331
332 /* Copy packet (failure will not stop the original)*/
333 m2 = m_dup(m, M_DONTWAIT);
334 if (m2) {
335 /* Deliver duplicate */
336 dup->stats.outOctets += m->m_pkthdr.len;
337 dup->stats.outFrames++;
338 NG_SEND_DATA_ONLY(error, dup->hook, m2);
339 }
340 }
341 /* Deliver frame out destination hook */
342 if (dest->hook) {
343 dest->stats.outOctets += m->m_pkthdr.len;
344 dest->stats.outFrames++;
345 NG_FWD_ITEM_HOOK(error, item, dest->hook);
346 } else
347 NG_FREE_ITEM(item);
348 return (error);
349 }
350
351 /*
352 * We are going to be shut down soon
353 *
354 * If we have both a left and right hook, then we probably want to extricate
355 * ourselves and leave the two peers still linked to each other. Otherwise we
356 * should just shut down as a normal node would.
357 */
358 static int
359 ngt_close(node_p node)
360 {
361 const sc_p privdata = NG_NODE_PRIVATE(node);
362
363 if (privdata->left.hook && privdata->right.hook)
364 ng_bypass(privdata->left.hook, privdata->right.hook);
365
366 return (0);
367 }
368
369 /*
370 * Shutdown processing
371 */
372 static int
373 ngt_shutdown(node_p node)
374 {
375 const sc_p privdata = NG_NODE_PRIVATE(node);
376
377 NG_NODE_SET_PRIVATE(node, NULL);
378 NG_NODE_UNREF(privdata->node);
379 FREE(privdata, M_NETGRAPH);
380 return (0);
381 }
382
383 /*
384 * Hook disconnection
385 */
386 static int
387 ngt_disconnect(hook_p hook)
388 {
389 struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook);
390
391 KASSERT(hinfo != NULL, ("%s: null info", __func__));
392 hinfo->hook = NULL;
393 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
394 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
395 ng_rmnode_self(NG_HOOK_NODE(hook));
396 return (0);
397 }
398
Cache object: c218ad7ec0ee44269ae38fc4d94f1348
|