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