FreeBSD kernel netgraph code
ng_tee.c
Go to the documentation of this file.
1
2/*
3 * ng_tee.c
4 */
5
6/*-
7 * Copyright (c) 1996-1999 Whistle Communications, Inc.
8 * All rights reserved.
9 *
10 * Subject to the following obligations and disclaimer of warranty, use and
11 * redistribution of this software, in source or object code forms, with or
12 * without modifications are expressly permitted by Whistle Communications;
13 * provided, however, that:
14 * 1. Any and all reproductions of the source or object code must include the
15 * copyright notice above and the following disclaimer of warranties; and
16 * 2. No rights are granted, in any manner or form, to use Whistle
17 * Communications, Inc. trademarks, including the mark "WHISTLE
18 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
19 * such appears in the above copyright notice or in the software.
20 *
21 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
22 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
23 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
24 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
26 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
27 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
28 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
29 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
30 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
31 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
32 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
37 * OF SUCH DAMAGE.
38 *
39 * Author: Julian Elischer <julian@freebsd.org>
40 *
41 * $FreeBSD$
42 * $Whistle: ng_tee.c,v 1.18 1999/11/01 09:24:52 julian Exp $
43 */
44
45/*
46 * This node is like the tee(1) command and is useful for ``snooping.''
47 * It has 4 hooks: left, right, left2right, and right2left. Data
48 * entering from the right is passed to the left and duplicated on
49 * right2left, and data entering from the left is passed to the right
50 * and duplicated on left2right. Data entering from left2right is
51 * sent to left, and data from right2left to right.
52 */
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/errno.h>
57#include <sys/kernel.h>
58#include <sys/malloc.h>
59#include <sys/mbuf.h>
60#include <netgraph/ng_message.h>
61#include <netgraph/netgraph.h>
62#include <netgraph/ng_parse.h>
63#include <netgraph/ng_tee.h>
64
65/* Per hook info */
66struct hookinfo {
68 struct hookinfo *dest, *dup;
70};
71typedef struct hookinfo *hi_p;
72
73/* Per node info */
74struct privdata {
75 struct hookinfo left;
79};
80typedef struct privdata *sc_p;
81
82/* Netgraph methods */
90
91/* Parse type for struct ng_tee_hookstat */
94static const struct ng_parse_type ng_tee_hookstat_type = {
97};
98
99/* Parse type for struct ng_tee_stats */
102static const struct ng_parse_type ng_tee_stats_type = {
105};
106
107/* List of commands and how to convert arguments to/from ASCII */
108static const struct ng_cmdlist ng_tee_cmds[] = {
109 {
112 "getstats",
113 NULL,
115 },
116 {
119 "clrstats",
120 NULL,
121 NULL
122 },
123 {
126 "getclrstats",
127 NULL,
129 },
130 { 0 }
131};
132
133/* Netgraph type descriptor */
134static struct ng_type ng_tee_typestruct = {
136 .name = NG_TEE_NODE_TYPE,
137 .constructor = ng_tee_constructor,
138 .rcvmsg = ng_tee_rcvmsg,
139 .close = ng_tee_close,
140 .shutdown = ng_tee_shutdown,
141 .newhook = ng_tee_newhook,
142 .rcvdata = ng_tee_rcvdata,
143 .disconnect = ng_tee_disconnect,
144 .cmdlist = ng_tee_cmds,
145};
147
148/*
149 * Node constructor
150 */
151static int
153{
155
156 privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
157
159 return (0);
160}
161
162/*
163 * Add a hook
164 */
165static int
166ng_tee_newhook(node_p node, hook_p hook, const char *name)
167{
169 hi_p hinfo;
170
171 /* Precalculate internal paths. */
172 if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) {
173 hinfo = &privdata->right;
174 if (privdata->left.dest)
176 privdata->left.dest = hinfo;
177 privdata->right2left.dest = hinfo;
178 } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) {
179 hinfo = &privdata->left;
180 if (privdata->right.dest)
182 privdata->right.dest = hinfo;
183 privdata->left2right.dest = hinfo;
184 } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) {
185 hinfo = &privdata->right2left;
186 if (privdata->right.dest)
187 privdata->right.dup = hinfo;
188 else
189 privdata->right.dest = hinfo;
190 } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) {
191 hinfo = &privdata->left2right;
192 if (privdata->left.dest)
193 privdata->left.dup = hinfo;
194 else
195 privdata->left.dest = hinfo;
196 } else
197 return (EINVAL);
198 hinfo->hook = hook;
199 bzero(&hinfo->stats, sizeof(hinfo->stats));
200 NG_HOOK_SET_PRIVATE(hook, hinfo);
201 return (0);
202}
203
204/*
205 * Receive a control message
206 */
207static int
208ng_tee_rcvmsg(node_p node, item_p item, hook_p lasthook)
209{
210 const sc_p sc = NG_NODE_PRIVATE(node);
211 struct ng_mesg *resp = NULL;
212 int error = 0;
213 struct ng_mesg *msg;
214
215 NGI_GET_MSG(item, msg);
216 switch (msg->header.typecookie) {
217 case NGM_TEE_COOKIE:
218 switch (msg->header.cmd) {
222 {
223 struct ng_tee_stats *stats;
224
225 if (msg->header.cmd != NGM_TEE_CLR_STATS) {
226 NG_MKRESPONSE(resp, msg,
227 sizeof(*stats), M_NOWAIT);
228 if (resp == NULL) {
229 error = ENOMEM;
230 goto done;
231 }
232 stats = (struct ng_tee_stats *)resp->data;
233 bcopy(&sc->right.stats, &stats->right,
234 sizeof(stats->right));
235 bcopy(&sc->left.stats, &stats->left,
236 sizeof(stats->left));
237 bcopy(&sc->right2left.stats, &stats->right2left,
238 sizeof(stats->right2left));
239 bcopy(&sc->left2right.stats, &stats->left2right,
240 sizeof(stats->left2right));
241 }
242 if (msg->header.cmd != NGM_TEE_GET_STATS) {
243 bzero(&sc->right.stats,
244 sizeof(sc->right.stats));
245 bzero(&sc->left.stats,
246 sizeof(sc->left.stats));
247 bzero(&sc->right2left.stats,
248 sizeof(sc->right2left.stats));
249 bzero(&sc->left2right.stats,
250 sizeof(sc->left2right.stats));
251 }
252 break;
253 }
254 default:
255 error = EINVAL;
256 break;
257 }
258 break;
259 case NGM_FLOW_COOKIE:
260 if (lasthook == sc->left.hook || lasthook == sc->right.hook) {
261 hi_p const hinfo = NG_HOOK_PRIVATE(lasthook);
262 if (hinfo && hinfo->dest) {
263 NGI_MSG(item) = msg;
264 NG_FWD_ITEM_HOOK(error, item, hinfo->dest->hook);
265 return (error);
266 }
267 }
268 break;
269 default:
270 error = EINVAL;
271 break;
272 }
273done:
274 NG_RESPOND_MSG(error, node, item, resp);
275 NG_FREE_MSG(msg);
276 return (error);
277}
278
279/*
280 * Receive data on a hook
281 *
282 * If data comes in the right link send a copy out right2left, and then
283 * send the original onwards out through the left link.
284 * Do the opposite for data coming in from the left link.
285 * Data coming in right2left or left2right is forwarded
286 * on through the appropriate destination hook as if it had come
287 * from the other side.
288 */
289static int
291{
292 const hi_p hinfo = NG_HOOK_PRIVATE(hook);
293 hi_p h;
294 int error = 0;
295 struct mbuf *m;
296
297 m = NGI_M(item);
298
299 /* Update stats on incoming hook */
300 hinfo->stats.inOctets += m->m_pkthdr.len;
301 hinfo->stats.inFrames++;
302
303 /* Duplicate packet if requried */
304 if (hinfo->dup) {
305 struct mbuf *m2;
306
307 /* Copy packet (failure will not stop the original)*/
308 m2 = m_dup(m, M_NOWAIT);
309 if (m2) {
310 /* Deliver duplicate */
311 h = hinfo->dup;
312 NG_SEND_DATA_ONLY(error, h->hook, m2);
313 if (error == 0) {
314 h->stats.outOctets += m->m_pkthdr.len;
315 h->stats.outFrames++;
316 }
317 }
318 }
319 /* Deliver frame out destination hook */
320 if (hinfo->dest) {
321 h = hinfo->dest;
322 h->stats.outOctets += m->m_pkthdr.len;
323 h->stats.outFrames++;
324 NG_FWD_ITEM_HOOK(error, item, h->hook);
325 } else
326 NG_FREE_ITEM(item);
327 return (error);
328}
329
330/*
331 * We are going to be shut down soon
332 *
333 * If we have both a left and right hook, then we probably want to extricate
334 * ourselves and leave the two peers still linked to each other. Otherwise we
335 * should just shut down as a normal node would.
336 */
337static int
339{
340 const sc_p privdata = NG_NODE_PRIVATE(node);
341
344
345 return (0);
346}
347
348/*
349 * Shutdown processing
350 */
351static int
353{
354 const sc_p privdata = NG_NODE_PRIVATE(node);
355
356 NG_NODE_SET_PRIVATE(node, NULL);
357 free(privdata, M_NETGRAPH);
358 NG_NODE_UNREF(node);
359 return (0);
360}
361
362/*
363 * Hook disconnection
364 */
365static int
367{
369 hi_p const hinfo = NG_HOOK_PRIVATE(hook);
370
371 KASSERT(hinfo != NULL, ("%s: null info", __func__));
372 hinfo->hook = NULL;
373
374 /* Recalculate internal paths. */
375 if (sc->left.dest == hinfo) {
376 sc->left.dest = sc->left.dup;
377 sc->left.dup = NULL;
378 } else if (sc->left.dup == hinfo)
379 sc->left.dup = NULL;
380 if (sc->right.dest == hinfo) {
381 sc->right.dest = sc->right.dup;
382 sc->right.dup = NULL;
383 } else if (sc->right.dup == hinfo)
384 sc->right.dup = NULL;
385 if (sc->left2right.dest == hinfo)
386 sc->left2right.dest = NULL;
387 if (sc->right2left.dest == hinfo)
388 sc->right2left.dest = NULL;
389
390 /* Die when last hook disconnected. */
391 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
394 return (0);
395}
#define NGI_M(i)
Definition: netgraph.h:833
#define NGI_MSG(i)
Definition: netgraph.h:834
#define NG_HOOK_NODE(hook)
Definition: netgraph.h:339
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
Definition: netgraph.h:105
#define NG_FWD_ITEM_HOOK(error, item, hook)
Definition: netgraph.h:898
int ng_disconnect_t(hook_p hook)
Definition: netgraph.h:107
#define NG_NODE_SET_PRIVATE(node, val)
Definition: netgraph.h:608
#define NG_RESPOND_MSG(error, here, item, resp)
Definition: netgraph.h:1025
#define NG_NODE_IS_VALID(node)
Definition: netgraph.h:610
#define NG_NODE_UNREF(node)
Definition: netgraph.h:607
#define NG_HOOK_SET_PRIVATE(hook, val)
Definition: netgraph.h:333
int ng_rmnode_self(node_p here)
Definition: ng_base.c:1609
#define NG_SEND_DATA_ONLY(error, hook, m)
Definition: netgraph.h:932
int ng_close_t(node_p node)
Definition: netgraph.h:100
int ng_rcvdata_t(hook_p hook, item_p item)
Definition: netgraph.h:106
int ng_shutdown_t(node_p node)
Definition: netgraph.h:101
#define NG_FREE_ITEM(item)
Definition: netgraph.h:847
int ng_constructor_t(node_p node)
Definition: netgraph.h:99
#define NG_FREE_MSG(msg)
Definition: netgraph.h:938
#define NG_ABI_VERSION
Definition: netgraph.h:77
int ng_bypass(hook_p hook1, hook_p hook2)
Definition: ng_base.c:1241
#define NG_NODE_NUMHOOKS(node)
Definition: netgraph.h:615
#define NGI_GET_MSG(i, m)
Definition: netgraph.h:858
#define NG_NODE_PRIVATE(node)
Definition: netgraph.h:609
int ng_newhook_t(node_p node, hook_p hook, const char *name)
Definition: netgraph.h:102
#define NG_HOOK_PRIVATE(hook)
Definition: netgraph.h:336
#define NG_MKRESPONSE(rsp, msg, len, how)
Definition: ng_message.h:396
#define NGM_FLOW_COOKIE
Definition: ng_message.h:152
const struct ng_parse_type ng_parse_struct_type
Definition: ng_parse.c:222
char *const name
Definition: ng_ppp.c:261
static ng_rcvdata_t ng_tee_rcvdata
Definition: ng_tee.c:88
static const struct ng_parse_struct_field ng_tee_hookstat_type_fields[]
Definition: ng_tee.c:93
static struct ng_type ng_tee_typestruct
Definition: ng_tee.c:134
static ng_shutdown_t ng_tee_shutdown
Definition: ng_tee.c:86
static ng_rcvmsg_t ng_tee_rcvmsg
Definition: ng_tee.c:84
static const struct ng_cmdlist ng_tee_cmds[]
Definition: ng_tee.c:108
static const struct ng_parse_type ng_tee_hookstat_type
Definition: ng_tee.c:94
static ng_constructor_t ng_tee_constructor
Definition: ng_tee.c:83
static ng_disconnect_t ng_tee_disconnect
Definition: ng_tee.c:89
struct hookinfo * hi_p
Definition: ng_tee.c:71
static const struct ng_parse_struct_field ng_tee_stats_type_fields[]
Definition: ng_tee.c:101
struct privdata * sc_p
Definition: ng_tee.c:80
static ng_close_t ng_tee_close
Definition: ng_tee.c:85
NETGRAPH_INIT(tee, &ng_tee_typestruct)
static const struct ng_parse_type ng_tee_stats_type
Definition: ng_tee.c:102
static ng_newhook_t ng_tee_newhook
Definition: ng_tee.c:87
#define NG_TEE_STATS_INFO(hstype)
Definition: ng_tee.h:84
#define NG_TEE_HOOK_RIGHT2LEFT
Definition: ng_tee.h:55
#define NGM_TEE_COOKIE
Definition: ng_tee.h:50
#define NG_TEE_HOOK_LEFT2RIGHT
Definition: ng_tee.h:56
#define NG_TEE_HOOK_LEFT
Definition: ng_tee.h:54
#define NG_TEE_NODE_TYPE
Definition: ng_tee.h:49
#define NG_TEE_HOOK_RIGHT
Definition: ng_tee.h:53
#define NG_TEE_HOOKSTAT_INFO
Definition: ng_tee.h:67
@ NGM_TEE_GETCLR_STATS
Definition: ng_tee.h:96
@ NGM_TEE_CLR_STATS
Definition: ng_tee.h:95
@ NGM_TEE_GET_STATS
Definition: ng_tee.h:94
hook_p dest
Definition: ng_car.c:62
hook_p hook
Definition: ng_car.c:61
struct hookinfo * dest
Definition: ng_tee.c:68
struct hookinfo * dup
Definition: ng_tee.c:68
struct ng_car_hookstats stats
Definition: ng_car.c:69
struct ng_async_stat stats
Definition: ng_async.c:86
u_int32_t typecookie
Definition: ng_message.h:66
struct ng_mesg::ng_msghdr header
char data[]
Definition: ng_message.h:69
u_int32_t version
Definition: netgraph.h:1077
struct hookinfo left
Definition: ng_tee.c:75
struct hookinfo right2left
Definition: ng_tee.c:78
struct hookinfo right
Definition: ng_tee.c:76
struct hookinfo left2right
Definition: ng_tee.c:77
Definition: ng_sscop.c:74