ng_gif.c revision 83998
1/*
2 * ng_gif.c
3 *
4 * Copyright 2001 The Aerospace Corporation.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * Copyright (c) 1996-2000 Whistle Communications, Inc.
29 * All rights reserved.
30 *
31 * Subject to the following obligations and disclaimer of warranty, use and
32 * redistribution of this software, in source or object code forms, with or
33 * without modifications are expressly permitted by Whistle Communications;
34 * provided, however, that:
35 * 1. Any and all reproductions of the source or object code must include the
36 *    copyright notice above and the following disclaimer of warranties; and
37 * 2. No rights are granted, in any manner or form, to use Whistle
38 *    Communications, Inc. trademarks, including the mark "WHISTLE
39 *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
40 *    such appears in the above copyright notice or in the software.
41 *
42 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
43 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
44 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
45 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
46 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
47 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
48 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
49 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
50 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
51 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
52 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
53 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
54 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
58 * OF SUCH DAMAGE.
59 *
60 * $FreeBSD: head/sys/netgraph/ng_gif.c 83998 2001-09-26 23:50:17Z brooks $
61 */
62
63/*
64 * ng_gif(4) netgraph node type
65 */
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/kernel.h>
70#include <sys/malloc.h>
71#include <sys/mbuf.h>
72#include <sys/errno.h>
73#include <sys/syslog.h>
74#include <sys/socket.h>
75
76#include <net/if.h>
77#include <net/route.h>
78#include <net/if_types.h>
79#include <net/if_var.h>
80#include <net/if_gif.h>
81
82#include <netgraph/ng_message.h>
83#include <netgraph/netgraph.h>
84#include <netgraph/ng_parse.h>
85#include <netgraph/ng_gif.h>
86
87#define IFP2NG(ifp)  ((struct ng_node *)((struct gif_softc *)(ifp))->gif_netgraph)
88
89/* Per-node private data */
90struct private {
91	struct ifnet	*ifp;		/* associated interface */
92	hook_p		lower;		/* lower OR orphan hook connection */
93	u_char		lowerOrphan;	/* whether lower is lower or orphan */
94};
95typedef struct private *priv_p;
96
97/* Functional hooks called from if_gif.c */
98static void	ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);
99static void	ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);
100static void	ng_gif_attach(struct ifnet *ifp);
101static void	ng_gif_detach(struct ifnet *ifp);
102
103/* Other functions */
104static void	ng_gif_input2(node_p node, struct mbuf **mp, int af);
105static int	ng_gif_glue_af(struct mbuf **mp, int af);
106static int	ng_gif_rcv_lower(node_p node, struct mbuf *m, meta_p meta);
107
108/* Netgraph node methods */
109static ng_constructor_t	ng_gif_constructor;
110static ng_rcvmsg_t	ng_gif_rcvmsg;
111static ng_shutdown_t	ng_gif_shutdown;
112static ng_newhook_t	ng_gif_newhook;
113static ng_connect_t	ng_gif_connect;
114static ng_rcvdata_t	ng_gif_rcvdata;
115static ng_disconnect_t	ng_gif_disconnect;
116static int		ng_gif_mod_event(module_t mod, int event, void *data);
117
118/* List of commands and how to convert arguments to/from ASCII */
119static const struct ng_cmdlist ng_gif_cmdlist[] = {
120	{
121	  NGM_GIF_COOKIE,
122	  NGM_GIF_GET_IFNAME,
123	  "getifname",
124	  NULL,
125	  &ng_parse_string_type
126	},
127	{
128	  NGM_GIF_COOKIE,
129	  NGM_GIF_GET_IFINDEX,
130	  "getifindex",
131	  NULL,
132	  &ng_parse_int32_type
133	},
134	{ 0 }
135};
136
137static struct ng_type ng_gif_typestruct = {
138	NG_ABI_VERSION,
139	NG_GIF_NODE_TYPE,
140	ng_gif_mod_event,
141	ng_gif_constructor,
142	ng_gif_rcvmsg,
143	ng_gif_shutdown,
144	ng_gif_newhook,
145	NULL,
146	ng_gif_connect,
147	ng_gif_rcvdata,
148	ng_gif_disconnect,
149	ng_gif_cmdlist,
150};
151MODULE_VERSION(ng_gif, 1);
152MODULE_DEPEND(ng_gif, if_gif, 1,1,1);
153NETGRAPH_INIT(gif, &ng_gif_typestruct);
154
155/******************************************************************
156		       GIF FUNCTION HOOKS
157******************************************************************/
158
159/*
160 * Handle a packet that has come in on an interface. We get to
161 * look at it here before any upper layer protocols do.
162 *
163 * NOTE: this function will get called at splimp()
164 */
165static void
166ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)
167{
168	const node_p node = IFP2NG(ifp);
169	const priv_p priv = NG_NODE_PRIVATE(node);
170
171	/* If "lower" hook not connected, let packet continue */
172	if (priv->lower == NULL || priv->lowerOrphan)
173		return;
174	ng_gif_input2(node, mp, af);
175}
176
177/*
178 * Handle a packet that has come in on an interface, and which
179 * does not match any of our known protocols (an ``orphan'').
180 *
181 * NOTE: this function will get called at splimp()
182 */
183static void
184ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
185{
186	const node_p node = IFP2NG(ifp);
187	const priv_p priv = NG_NODE_PRIVATE(node);
188
189	/* If "orphan" hook not connected, let packet continue */
190	if (priv->lower == NULL || !priv->lowerOrphan) {
191		m_freem(m);
192		return;
193	}
194	ng_gif_input2(node, &m, af);
195	if (m != NULL)
196		m_freem(m);
197}
198
199/*
200 * Handle a packet that has come in on a gif interface.
201 * Attach the address family to the mbuf for later use.
202 *
203 * NOTE: this function will get called at splimp()
204 */
205static void
206ng_gif_input2(node_p node, struct mbuf **mp, int af)
207{
208	const priv_p priv = NG_NODE_PRIVATE(node);
209	int error;
210
211	/* Glue address family on */
212	if ((error = ng_gif_glue_af(mp, af)) != 0)
213		return;
214
215	/* Send out lower/orphan hook */
216	NG_SEND_DATA_ONLY(error, priv->lower, *mp);
217	*mp = NULL;
218}
219
220/*
221 * A new gif interface has been attached.
222 * Create a new node for it, etc.
223 */
224static void
225ng_gif_attach(struct ifnet *ifp)
226{
227	char name[IFNAMSIZ + 1];
228	priv_p priv;
229	node_p node;
230
231	/* Create node */
232	KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__));
233	snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit);
234	if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
235		log(LOG_ERR, "%s: can't %s for %s\n",
236		    __FUNCTION__, "create node", name);
237		return;
238	}
239
240	/* Allocate private data */
241	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
242	if (priv == NULL) {
243		log(LOG_ERR, "%s: can't %s for %s\n",
244		    __FUNCTION__, "allocate memory", name);
245		NG_NODE_UNREF(node);
246		return;
247	}
248	NG_NODE_SET_PRIVATE(node, priv);
249	priv->ifp = ifp;
250	IFP2NG(ifp) = node;
251
252	/* Try to give the node the same name as the interface */
253	if (ng_name_node(node, name) != 0) {
254		log(LOG_WARNING, "%s: can't name node %s\n",
255		    __FUNCTION__, name);
256	}
257}
258
259/*
260 * An Ethernet interface is being detached.
261 * REALLY Destroy its node.
262 */
263static void
264ng_gif_detach(struct ifnet *ifp)
265{
266	const node_p node = IFP2NG(ifp);
267	const priv_p priv = NG_NODE_PRIVATE(node);
268
269	if (node == NULL)		/* no node (why not?), ignore */
270		return;
271	NG_NODE_REALLY_DIE(node);	/* Force real removal of node */
272	/*
273	 * We can't assume the ifnet is still around when we run shutdown
274	 * So zap it now. XXX We HOPE that anything running at this time
275	 * handles it (as it should in the non netgraph case).
276	 */
277	IFP2NG(ifp) = NULL;
278	priv->ifp = NULL;	/* XXX race if interrupted an output packet */
279	ng_rmnode_self(node);		/* remove all netgraph parts */
280}
281
282/*
283 * Optimization for gluing the Ethernet header back onto
284 * the front of an incoming packet.
285 */
286static int
287ng_gif_glue_af(struct mbuf **mp, int af)
288{
289	struct mbuf *m = *mp;
290	int error = 0;
291	sa_family_t tmp_af;
292
293	tmp_af = (sa_family_t) af;
294
295	/*
296	 * XXX: should try to bring back some of the optimizations from
297	 * ng_ether.c
298	 */
299
300	/*
301	 * Doing anything more is likely to get more
302	 * expensive than it's worth..
303	 * it's probable that everything else is in one
304	 * big lump. The next node will do an m_pullup()
305	 * for exactly the amount of data it needs and
306	 * hopefully everything after that will not
307	 * need one. So let's just use M_PREPEND.
308	 */
309	M_PREPEND(m, sizeof (tmp_af), M_DONTWAIT);
310	if (m == NULL) {
311		error = ENOBUFS;
312		goto done;
313	}
314
315#if 0
316copy:
317#endif
318	/* Copy header and return (possibly new) mbuf */
319	*mtod(m, sa_family_t *) = tmp_af;
320#if 0
321	bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
322#endif
323done:
324	*mp = m;
325	return error;
326}
327
328/******************************************************************
329		    NETGRAPH NODE METHODS
330******************************************************************/
331
332/*
333 * It is not possible or allowable to create a node of this type.
334 * Nodes get created when the interface is attached (or, when
335 * this node type's KLD is loaded).
336 */
337static int
338ng_gif_constructor(node_p node)
339{
340	return (EINVAL);
341}
342
343/*
344 * Check for attaching a new hook.
345 */
346static	int
347ng_gif_newhook(node_p node, hook_p hook, const char *name)
348{
349	const priv_p priv = NG_NODE_PRIVATE(node);
350	u_char orphan = priv->lowerOrphan;
351	hook_p *hookptr;
352
353	/* Divert hook is an alias for lower */
354	if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
355		name = NG_GIF_HOOK_LOWER;
356
357	/* Which hook? */
358	if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
359		hookptr = &priv->lower;
360		orphan = 0;
361	} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
362		hookptr = &priv->lower;
363		orphan = 1;
364	} else
365		return (EINVAL);
366
367	/* Check if already connected (shouldn't be, but doesn't hurt) */
368	if (*hookptr != NULL)
369		return (EISCONN);
370
371	/* OK */
372	*hookptr = hook;
373	priv->lowerOrphan = orphan;
374	return (0);
375}
376
377/*
378 * Hooks are attached, adjust to force queueing.
379 * We don't really care which hook it is.
380 * they should all be queuing for outgoing data.
381 */
382static	int
383ng_gif_connect(hook_p hook)
384{
385	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
386	return (0);
387}
388
389/*
390 * Receive an incoming control message.
391 */
392static int
393ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
394{
395	const priv_p priv = NG_NODE_PRIVATE(node);
396	struct ng_mesg *resp = NULL;
397	int error = 0;
398	struct ng_mesg *msg;
399
400	NGI_GET_MSG(item, msg);
401	switch (msg->header.typecookie) {
402	case NGM_GIF_COOKIE:
403		switch (msg->header.cmd) {
404		case NGM_GIF_GET_IFNAME:
405			NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
406			if (resp == NULL) {
407				error = ENOMEM;
408				break;
409			}
410			snprintf(resp->data, IFNAMSIZ + 1,
411			    "%s%d", priv->ifp->if_name, priv->ifp->if_unit);
412			break;
413		case NGM_GIF_GET_IFINDEX:
414			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
415			if (resp == NULL) {
416				error = ENOMEM;
417				break;
418			}
419			*((u_int32_t *)resp->data) = priv->ifp->if_index;
420			break;
421		default:
422			error = EINVAL;
423			break;
424		}
425		break;
426	default:
427		error = EINVAL;
428		break;
429	}
430	NG_RESPOND_MSG(error, node, item, resp);
431	NG_FREE_MSG(msg);
432	return (error);
433}
434
435/*
436 * Receive data on a hook.
437 */
438static int
439ng_gif_rcvdata(hook_p hook, item_p item)
440{
441	const node_p node = NG_HOOK_NODE(hook);
442	const priv_p priv = NG_NODE_PRIVATE(node);
443	struct mbuf *m;
444	meta_p meta;
445
446	NGI_GET_M(item, m);
447	NGI_GET_META(item, meta);
448	NG_FREE_ITEM(item);
449	if (hook == priv->lower)
450		return ng_gif_rcv_lower(node, m, meta);
451	panic("%s: weird hook", __FUNCTION__);
452}
453
454/*
455 * Handle an mbuf received on the "lower" hook.
456 */
457static int
458ng_gif_rcv_lower(node_p node, struct mbuf *m, meta_p meta)
459{
460	struct sockaddr	dst;
461	const priv_p priv = NG_NODE_PRIVATE(node);
462
463	bzero(&dst, sizeof(dst));
464
465	/* We don't process metadata. */
466	NG_FREE_META(meta);
467
468	/* Make sure header is fully pulled up */
469	if (m->m_pkthdr.len < sizeof(sa_family_t)) {
470		NG_FREE_M(m);
471		return (EINVAL);
472	}
473	if (m->m_len < sizeof(sa_family_t)
474	    && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
475		return (ENOBUFS);
476	}
477
478	dst.sa_family = *mtod(m, sa_family_t *);
479	m_adj(m, sizeof(sa_family_t));
480
481	/* Send it on its way */
482	/*
483	 * XXX: gif_output only uses dst for the family and passes the
484	 * fourth argument (rt) to in{,6}_gif_output which ignore it.
485	 * If this changes ng_gif will probably break.
486	 */
487	return gif_output(priv->ifp, m, &dst, NULL);
488}
489
490/*
491 * Shutdown node. This resets the node but does not remove it
492 * unless the REALLY_DIE flag is set.
493 */
494static int
495ng_gif_shutdown(node_p node)
496{
497	const priv_p priv = NG_NODE_PRIVATE(node);
498
499	if (node->nd_flags & NG_REALLY_DIE) {
500		/*
501		 * WE came here because the gif interface is being destroyed,
502		 * so stop being persistant.
503		 * Actually undo all the things we did on creation.
504		 * Assume the ifp has already been freed.
505		 */
506		NG_NODE_SET_PRIVATE(node, NULL);
507		FREE(priv, M_NETGRAPH);
508		NG_NODE_UNREF(node);	/* free node itself */
509		return (0);
510	}
511	node->nd_flags &= ~NG_INVALID;	/* Signal ng_rmnode we are persisant */
512	return (0);
513}
514
515/*
516 * Hook disconnection.
517 */
518static int
519ng_gif_disconnect(hook_p hook)
520{
521	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
522
523	if (hook == priv->lower) {
524		priv->lower = NULL;
525		priv->lowerOrphan = 0;
526	} else
527		panic("%s: weird hook", __FUNCTION__);
528	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
529	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
530		ng_rmnode_self(NG_HOOK_NODE(hook));	/* reset node */
531
532	return (0);
533}
534
535/******************************************************************
536		    	INITIALIZATION
537******************************************************************/
538
539/*
540 * Handle loading and unloading for this node type.
541 */
542static int
543ng_gif_mod_event(module_t mod, int event, void *data)
544{
545	struct ifnet *ifp;
546	int error = 0;
547	int s;
548
549	s = splnet();
550	switch (event) {
551	case MOD_LOAD:
552
553		/* Register function hooks */
554		if (ng_gif_attach_p != NULL) {
555			error = EEXIST;
556			break;
557		}
558		ng_gif_attach_p = ng_gif_attach;
559		ng_gif_detach_p = ng_gif_detach;
560		ng_gif_input_p = ng_gif_input;
561		ng_gif_input_orphan_p = ng_gif_input_orphan;
562
563		/* Create nodes for any already-existing gif interfaces */
564		TAILQ_FOREACH(ifp, &ifnet, if_link) {
565			if (ifp->if_type == IFT_GIF)
566				ng_gif_attach(ifp);
567		}
568		break;
569
570	case MOD_UNLOAD:
571
572		/*
573		 * Note that the base code won't try to unload us until
574		 * all nodes have been removed, and that can't happen
575		 * until all gif interfaces are destroyed. In any
576		 * case, we know there are no nodes left if the action
577		 * is MOD_UNLOAD, so there's no need to detach any nodes.
578		 *
579		 * XXX: what about manual unloads?!?
580		 */
581
582		/* Unregister function hooks */
583		ng_gif_attach_p = NULL;
584		ng_gif_detach_p = NULL;
585		ng_gif_input_p = NULL;
586		ng_gif_input_orphan_p = NULL;
587		break;
588
589	default:
590		error = EOPNOTSUPP;
591		break;
592	}
593	splx(s);
594	return (error);
595}
596
597