194408d94SBrooks Davis /*
294408d94SBrooks Davis * ng_gif.c
3c398230bSWarner Losh */
4c398230bSWarner Losh
5c398230bSWarner Losh /*-
6fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause
7fe267a55SPedro F. Giffuni *
894408d94SBrooks Davis * Copyright 2001 The Aerospace Corporation. All rights reserved.
994408d94SBrooks Davis *
1094408d94SBrooks Davis * Redistribution and use in source and binary forms, with or without
1194408d94SBrooks Davis * modification, are permitted provided that the following conditions
1294408d94SBrooks Davis * are met:
13cf776d81SBrooks Davis *
1494408d94SBrooks Davis * 1. Redistributions of source code must retain the above copyright
15cf776d81SBrooks Davis * notice, this list of conditions, and the following disclaimer.
1694408d94SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright
17cf776d81SBrooks Davis * notice, this list of conditions, and the following disclaimer in the
1894408d94SBrooks Davis * documentation and/or other materials provided with the distribution.
19cf776d81SBrooks Davis * 3. The name of The Aerospace Corporation may not be used to endorse or
20cf776d81SBrooks Davis * promote products derived from this software.
2194408d94SBrooks Davis *
2294408d94SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
2394408d94SBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2494408d94SBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2594408d94SBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
2694408d94SBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2794408d94SBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2894408d94SBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2994408d94SBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3094408d94SBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3194408d94SBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3294408d94SBrooks Davis * SUCH DAMAGE.
3394408d94SBrooks Davis *
3494408d94SBrooks Davis *
3594408d94SBrooks Davis * Copyright (c) 1996-2000 Whistle Communications, Inc.
3694408d94SBrooks Davis * All rights reserved.
3794408d94SBrooks Davis *
3894408d94SBrooks Davis * Subject to the following obligations and disclaimer of warranty, use and
3994408d94SBrooks Davis * redistribution of this software, in source or object code forms, with or
4094408d94SBrooks Davis * without modifications are expressly permitted by Whistle Communications;
4194408d94SBrooks Davis * provided, however, that:
4294408d94SBrooks Davis * 1. Any and all reproductions of the source or object code must include the
4394408d94SBrooks Davis * copyright notice above and the following disclaimer of warranties; and
4494408d94SBrooks Davis * 2. No rights are granted, in any manner or form, to use Whistle
4594408d94SBrooks Davis * Communications, Inc. trademarks, including the mark "WHISTLE
4694408d94SBrooks Davis * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
4794408d94SBrooks Davis * such appears in the above copyright notice or in the software.
4894408d94SBrooks Davis *
4994408d94SBrooks Davis * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
5094408d94SBrooks Davis * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
5194408d94SBrooks Davis * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
5294408d94SBrooks Davis * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
5394408d94SBrooks Davis * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
5494408d94SBrooks Davis * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
5594408d94SBrooks Davis * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
5694408d94SBrooks Davis * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
5794408d94SBrooks Davis * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
5894408d94SBrooks Davis * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
5994408d94SBrooks Davis * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
6094408d94SBrooks Davis * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
6194408d94SBrooks Davis * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
6294408d94SBrooks Davis * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6394408d94SBrooks Davis * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
6494408d94SBrooks Davis * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
6594408d94SBrooks Davis * OF SUCH DAMAGE.
6694408d94SBrooks Davis */
6794408d94SBrooks Davis
6894408d94SBrooks Davis /*
6994408d94SBrooks Davis * ng_gif(4) netgraph node type
7094408d94SBrooks Davis */
7194408d94SBrooks Davis #include <sys/param.h>
7294408d94SBrooks Davis #include <sys/systm.h>
7394408d94SBrooks Davis #include <sys/kernel.h>
7494408d94SBrooks Davis #include <sys/malloc.h>
7594408d94SBrooks Davis #include <sys/mbuf.h>
7694408d94SBrooks Davis #include <sys/errno.h>
7794408d94SBrooks Davis #include <sys/syslog.h>
7894408d94SBrooks Davis #include <sys/socket.h>
7994408d94SBrooks Davis
8094408d94SBrooks Davis #include <net/if.h>
8194408d94SBrooks Davis #include <net/route.h>
8294408d94SBrooks Davis #include <net/if_types.h>
8394408d94SBrooks Davis #include <net/if_var.h>
8494408d94SBrooks Davis #include <net/if_gif.h>
85*3d0d5b21SJustin Hibbits #include <net/if_private.h>
864b79449eSBjoern A. Zeeb #include <net/vnet.h>
8794408d94SBrooks Davis
8894408d94SBrooks Davis #include <netgraph/ng_message.h>
8994408d94SBrooks Davis #include <netgraph/netgraph.h>
9094408d94SBrooks Davis #include <netgraph/ng_parse.h>
9194408d94SBrooks Davis #include <netgraph/ng_gif.h>
9294408d94SBrooks Davis
93fc74a9f9SBrooks Davis #define IFP2NG(ifp) ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph)
94fc74a9f9SBrooks Davis #define IFP2NG_SET(ifp, val) (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val))
9594408d94SBrooks Davis
9694408d94SBrooks Davis /* Per-node private data */
9794408d94SBrooks Davis struct private {
9894408d94SBrooks Davis struct ifnet *ifp; /* associated interface */
9994408d94SBrooks Davis hook_p lower; /* lower OR orphan hook connection */
10094408d94SBrooks Davis u_char lowerOrphan; /* whether lower is lower or orphan */
10194408d94SBrooks Davis };
10294408d94SBrooks Davis typedef struct private *priv_p;
10394408d94SBrooks Davis
10494408d94SBrooks Davis /* Functional hooks called from if_gif.c */
10594408d94SBrooks Davis static void ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);
10694408d94SBrooks Davis static void ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);
10794408d94SBrooks Davis static void ng_gif_attach(struct ifnet *ifp);
10894408d94SBrooks Davis static void ng_gif_detach(struct ifnet *ifp);
10994408d94SBrooks Davis
11094408d94SBrooks Davis /* Other functions */
11194408d94SBrooks Davis static void ng_gif_input2(node_p node, struct mbuf **mp, int af);
11294408d94SBrooks Davis static int ng_gif_glue_af(struct mbuf **mp, int af);
1133ca24c28SJulian Elischer static int ng_gif_rcv_lower(node_p node, struct mbuf *m);
11494408d94SBrooks Davis
11594408d94SBrooks Davis /* Netgraph node methods */
11694408d94SBrooks Davis static ng_constructor_t ng_gif_constructor;
11794408d94SBrooks Davis static ng_rcvmsg_t ng_gif_rcvmsg;
11894408d94SBrooks Davis static ng_shutdown_t ng_gif_shutdown;
11994408d94SBrooks Davis static ng_newhook_t ng_gif_newhook;
12094408d94SBrooks Davis static ng_connect_t ng_gif_connect;
12194408d94SBrooks Davis static ng_rcvdata_t ng_gif_rcvdata;
12294408d94SBrooks Davis static ng_disconnect_t ng_gif_disconnect;
12394408d94SBrooks Davis static int ng_gif_mod_event(module_t mod, int event, void *data);
12494408d94SBrooks Davis
12594408d94SBrooks Davis /* List of commands and how to convert arguments to/from ASCII */
12694408d94SBrooks Davis static const struct ng_cmdlist ng_gif_cmdlist[] = {
12794408d94SBrooks Davis {
12894408d94SBrooks Davis NGM_GIF_COOKIE,
12994408d94SBrooks Davis NGM_GIF_GET_IFNAME,
13094408d94SBrooks Davis "getifname",
13194408d94SBrooks Davis NULL,
13294408d94SBrooks Davis &ng_parse_string_type
13394408d94SBrooks Davis },
13494408d94SBrooks Davis {
13594408d94SBrooks Davis NGM_GIF_COOKIE,
13694408d94SBrooks Davis NGM_GIF_GET_IFINDEX,
13794408d94SBrooks Davis "getifindex",
13894408d94SBrooks Davis NULL,
13994408d94SBrooks Davis &ng_parse_int32_type
14094408d94SBrooks Davis },
14194408d94SBrooks Davis { 0 }
14294408d94SBrooks Davis };
14394408d94SBrooks Davis
14494408d94SBrooks Davis static struct ng_type ng_gif_typestruct = {
145f8aae777SJulian Elischer .version = NG_ABI_VERSION,
146f8aae777SJulian Elischer .name = NG_GIF_NODE_TYPE,
147f8aae777SJulian Elischer .mod_event = ng_gif_mod_event,
148f8aae777SJulian Elischer .constructor = ng_gif_constructor,
149f8aae777SJulian Elischer .rcvmsg = ng_gif_rcvmsg,
150f8aae777SJulian Elischer .shutdown = ng_gif_shutdown,
151f8aae777SJulian Elischer .newhook = ng_gif_newhook,
152f8aae777SJulian Elischer .connect = ng_gif_connect,
153f8aae777SJulian Elischer .rcvdata = ng_gif_rcvdata,
154f8aae777SJulian Elischer .disconnect = ng_gif_disconnect,
155f8aae777SJulian Elischer .cmdlist = ng_gif_cmdlist,
15694408d94SBrooks Davis };
15794408d94SBrooks Davis MODULE_DEPEND(ng_gif, if_gif, 1,1,1);
15894408d94SBrooks Davis NETGRAPH_INIT(gif, &ng_gif_typestruct);
15994408d94SBrooks Davis
16094408d94SBrooks Davis /******************************************************************
16194408d94SBrooks Davis GIF FUNCTION HOOKS
16294408d94SBrooks Davis ******************************************************************/
16394408d94SBrooks Davis
16494408d94SBrooks Davis /*
16594408d94SBrooks Davis * Handle a packet that has come in on an interface. We get to
16694408d94SBrooks Davis * look at it here before any upper layer protocols do.
16794408d94SBrooks Davis */
16894408d94SBrooks Davis static void
ng_gif_input(struct ifnet * ifp,struct mbuf ** mp,int af)16994408d94SBrooks Davis ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)
17094408d94SBrooks Davis {
17194408d94SBrooks Davis const node_p node = IFP2NG(ifp);
17294408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
17394408d94SBrooks Davis
17494408d94SBrooks Davis /* If "lower" hook not connected, let packet continue */
17594408d94SBrooks Davis if (priv->lower == NULL || priv->lowerOrphan)
17694408d94SBrooks Davis return;
17794408d94SBrooks Davis ng_gif_input2(node, mp, af);
17894408d94SBrooks Davis }
17994408d94SBrooks Davis
18094408d94SBrooks Davis /*
18194408d94SBrooks Davis * Handle a packet that has come in on an interface, and which
18294408d94SBrooks Davis * does not match any of our known protocols (an ``orphan'').
18394408d94SBrooks Davis */
18494408d94SBrooks Davis static void
ng_gif_input_orphan(struct ifnet * ifp,struct mbuf * m,int af)18594408d94SBrooks Davis ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)
18694408d94SBrooks Davis {
18794408d94SBrooks Davis const node_p node = IFP2NG(ifp);
18894408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
18994408d94SBrooks Davis
19094408d94SBrooks Davis /* If "orphan" hook not connected, let packet continue */
19194408d94SBrooks Davis if (priv->lower == NULL || !priv->lowerOrphan) {
19294408d94SBrooks Davis m_freem(m);
19394408d94SBrooks Davis return;
19494408d94SBrooks Davis }
19594408d94SBrooks Davis ng_gif_input2(node, &m, af);
19694408d94SBrooks Davis if (m != NULL)
19794408d94SBrooks Davis m_freem(m);
19894408d94SBrooks Davis }
19994408d94SBrooks Davis
20094408d94SBrooks Davis /*
20194408d94SBrooks Davis * Handle a packet that has come in on a gif interface.
20294408d94SBrooks Davis * Attach the address family to the mbuf for later use.
20394408d94SBrooks Davis */
20494408d94SBrooks Davis static void
ng_gif_input2(node_p node,struct mbuf ** mp,int af)20594408d94SBrooks Davis ng_gif_input2(node_p node, struct mbuf **mp, int af)
20694408d94SBrooks Davis {
20794408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
20894408d94SBrooks Davis int error;
20994408d94SBrooks Davis
21094408d94SBrooks Davis /* Glue address family on */
21194408d94SBrooks Davis if ((error = ng_gif_glue_af(mp, af)) != 0)
21294408d94SBrooks Davis return;
21394408d94SBrooks Davis
21494408d94SBrooks Davis /* Send out lower/orphan hook */
21594408d94SBrooks Davis NG_SEND_DATA_ONLY(error, priv->lower, *mp);
21694408d94SBrooks Davis *mp = NULL;
21794408d94SBrooks Davis }
21894408d94SBrooks Davis
21994408d94SBrooks Davis /*
22094408d94SBrooks Davis * A new gif interface has been attached.
22194408d94SBrooks Davis * Create a new node for it, etc.
22294408d94SBrooks Davis */
22394408d94SBrooks Davis static void
ng_gif_attach(struct ifnet * ifp)22494408d94SBrooks Davis ng_gif_attach(struct ifnet *ifp)
22594408d94SBrooks Davis {
22694408d94SBrooks Davis priv_p priv;
22794408d94SBrooks Davis node_p node;
22894408d94SBrooks Davis
22994408d94SBrooks Davis /* Create node */
2306e551fb6SDavid E. O'Brien KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
23194408d94SBrooks Davis if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {
23294408d94SBrooks Davis log(LOG_ERR, "%s: can't %s for %s\n",
2339bf40edeSBrooks Davis __func__, "create node", ifp->if_xname);
23494408d94SBrooks Davis return;
23594408d94SBrooks Davis }
23694408d94SBrooks Davis
23794408d94SBrooks Davis /* Allocate private data */
2381ede983cSDag-Erling Smørgrav priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
23994408d94SBrooks Davis if (priv == NULL) {
24094408d94SBrooks Davis log(LOG_ERR, "%s: can't %s for %s\n",
2419bf40edeSBrooks Davis __func__, "allocate memory", ifp->if_xname);
24294408d94SBrooks Davis NG_NODE_UNREF(node);
24394408d94SBrooks Davis return;
24494408d94SBrooks Davis }
24594408d94SBrooks Davis NG_NODE_SET_PRIVATE(node, priv);
24694408d94SBrooks Davis priv->ifp = ifp;
247445e045bSAlexander Kabaev IFP2NG_SET(ifp, node);
24894408d94SBrooks Davis
24994408d94SBrooks Davis /* Try to give the node the same name as the interface */
2509bf40edeSBrooks Davis if (ng_name_node(node, ifp->if_xname) != 0) {
25194408d94SBrooks Davis log(LOG_WARNING, "%s: can't name node %s\n",
2529bf40edeSBrooks Davis __func__, ifp->if_xname);
25394408d94SBrooks Davis }
25494408d94SBrooks Davis }
25594408d94SBrooks Davis
25694408d94SBrooks Davis /*
2577360079aSBrooks Davis * An interface is being detached.
25894408d94SBrooks Davis * REALLY Destroy its node.
25994408d94SBrooks Davis */
26094408d94SBrooks Davis static void
ng_gif_detach(struct ifnet * ifp)26194408d94SBrooks Davis ng_gif_detach(struct ifnet *ifp)
26294408d94SBrooks Davis {
26394408d94SBrooks Davis const node_p node = IFP2NG(ifp);
264917a7daaSPoul-Henning Kamp priv_p priv;
26594408d94SBrooks Davis
26694408d94SBrooks Davis if (node == NULL) /* no node (why not?), ignore */
26794408d94SBrooks Davis return;
2683f54070bSColin Percival priv = NG_NODE_PRIVATE(node);
26994408d94SBrooks Davis NG_NODE_REALLY_DIE(node); /* Force real removal of node */
27094408d94SBrooks Davis /*
27194408d94SBrooks Davis * We can't assume the ifnet is still around when we run shutdown
27294408d94SBrooks Davis * So zap it now. XXX We HOPE that anything running at this time
27394408d94SBrooks Davis * handles it (as it should in the non netgraph case).
27494408d94SBrooks Davis */
275445e045bSAlexander Kabaev IFP2NG_SET(ifp, NULL);
27694408d94SBrooks Davis priv->ifp = NULL; /* XXX race if interrupted an output packet */
27794408d94SBrooks Davis ng_rmnode_self(node); /* remove all netgraph parts */
27894408d94SBrooks Davis }
27994408d94SBrooks Davis
28094408d94SBrooks Davis /*
2817360079aSBrooks Davis * Optimization for gluing the address family onto
28294408d94SBrooks Davis * the front of an incoming packet.
28394408d94SBrooks Davis */
28494408d94SBrooks Davis static int
ng_gif_glue_af(struct mbuf ** mp,int af)28594408d94SBrooks Davis ng_gif_glue_af(struct mbuf **mp, int af)
28694408d94SBrooks Davis {
28794408d94SBrooks Davis struct mbuf *m = *mp;
28894408d94SBrooks Davis int error = 0;
28994408d94SBrooks Davis sa_family_t tmp_af;
29094408d94SBrooks Davis
29194408d94SBrooks Davis tmp_af = (sa_family_t) af;
29294408d94SBrooks Davis
29394408d94SBrooks Davis /*
29494408d94SBrooks Davis * XXX: should try to bring back some of the optimizations from
29594408d94SBrooks Davis * ng_ether.c
29694408d94SBrooks Davis */
29794408d94SBrooks Davis
29894408d94SBrooks Davis /*
29994408d94SBrooks Davis * Doing anything more is likely to get more
30094408d94SBrooks Davis * expensive than it's worth..
30194408d94SBrooks Davis * it's probable that everything else is in one
30294408d94SBrooks Davis * big lump. The next node will do an m_pullup()
30394408d94SBrooks Davis * for exactly the amount of data it needs and
30494408d94SBrooks Davis * hopefully everything after that will not
30594408d94SBrooks Davis * need one. So let's just use M_PREPEND.
30694408d94SBrooks Davis */
307eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof (tmp_af), M_NOWAIT);
30894408d94SBrooks Davis if (m == NULL) {
30994408d94SBrooks Davis error = ENOBUFS;
31094408d94SBrooks Davis goto done;
31194408d94SBrooks Davis }
31294408d94SBrooks Davis
31394408d94SBrooks Davis #if 0
31494408d94SBrooks Davis copy:
31594408d94SBrooks Davis #endif
31694408d94SBrooks Davis /* Copy header and return (possibly new) mbuf */
31794408d94SBrooks Davis *mtod(m, sa_family_t *) = tmp_af;
31894408d94SBrooks Davis #if 0
31994408d94SBrooks Davis bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));
32094408d94SBrooks Davis #endif
32194408d94SBrooks Davis done:
32294408d94SBrooks Davis *mp = m;
32394408d94SBrooks Davis return error;
32494408d94SBrooks Davis }
32594408d94SBrooks Davis
32694408d94SBrooks Davis /******************************************************************
32794408d94SBrooks Davis NETGRAPH NODE METHODS
32894408d94SBrooks Davis ******************************************************************/
32994408d94SBrooks Davis
33094408d94SBrooks Davis /*
33194408d94SBrooks Davis * It is not possible or allowable to create a node of this type.
33294408d94SBrooks Davis * Nodes get created when the interface is attached (or, when
33394408d94SBrooks Davis * this node type's KLD is loaded).
33494408d94SBrooks Davis */
33594408d94SBrooks Davis static int
ng_gif_constructor(node_p node)33694408d94SBrooks Davis ng_gif_constructor(node_p node)
33794408d94SBrooks Davis {
33894408d94SBrooks Davis return (EINVAL);
33994408d94SBrooks Davis }
34094408d94SBrooks Davis
34194408d94SBrooks Davis /*
34294408d94SBrooks Davis * Check for attaching a new hook.
34394408d94SBrooks Davis */
34494408d94SBrooks Davis static int
ng_gif_newhook(node_p node,hook_p hook,const char * name)34594408d94SBrooks Davis ng_gif_newhook(node_p node, hook_p hook, const char *name)
34694408d94SBrooks Davis {
34794408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
34894408d94SBrooks Davis u_char orphan = priv->lowerOrphan;
34994408d94SBrooks Davis hook_p *hookptr;
35094408d94SBrooks Davis
35194408d94SBrooks Davis /* Divert hook is an alias for lower */
35294408d94SBrooks Davis if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)
35394408d94SBrooks Davis name = NG_GIF_HOOK_LOWER;
35494408d94SBrooks Davis
35594408d94SBrooks Davis /* Which hook? */
35694408d94SBrooks Davis if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {
35794408d94SBrooks Davis hookptr = &priv->lower;
35894408d94SBrooks Davis orphan = 0;
35994408d94SBrooks Davis } else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {
36094408d94SBrooks Davis hookptr = &priv->lower;
36194408d94SBrooks Davis orphan = 1;
36294408d94SBrooks Davis } else
36394408d94SBrooks Davis return (EINVAL);
36494408d94SBrooks Davis
36594408d94SBrooks Davis /* Check if already connected (shouldn't be, but doesn't hurt) */
36694408d94SBrooks Davis if (*hookptr != NULL)
36794408d94SBrooks Davis return (EISCONN);
36894408d94SBrooks Davis
36994408d94SBrooks Davis /* OK */
37094408d94SBrooks Davis *hookptr = hook;
37194408d94SBrooks Davis priv->lowerOrphan = orphan;
37294408d94SBrooks Davis return (0);
37394408d94SBrooks Davis }
37494408d94SBrooks Davis
37594408d94SBrooks Davis /*
37694408d94SBrooks Davis * Hooks are attached, adjust to force queueing.
37794408d94SBrooks Davis * We don't really care which hook it is.
37894408d94SBrooks Davis * they should all be queuing for outgoing data.
37994408d94SBrooks Davis */
38094408d94SBrooks Davis static int
ng_gif_connect(hook_p hook)38194408d94SBrooks Davis ng_gif_connect(hook_p hook)
38294408d94SBrooks Davis {
38394408d94SBrooks Davis NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
38494408d94SBrooks Davis return (0);
38594408d94SBrooks Davis }
38694408d94SBrooks Davis
38794408d94SBrooks Davis /*
38894408d94SBrooks Davis * Receive an incoming control message.
38994408d94SBrooks Davis */
39094408d94SBrooks Davis static int
ng_gif_rcvmsg(node_p node,item_p item,hook_p lasthook)39194408d94SBrooks Davis ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)
39294408d94SBrooks Davis {
39394408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
39494408d94SBrooks Davis struct ng_mesg *resp = NULL;
39594408d94SBrooks Davis int error = 0;
39694408d94SBrooks Davis struct ng_mesg *msg;
39794408d94SBrooks Davis
39894408d94SBrooks Davis NGI_GET_MSG(item, msg);
39994408d94SBrooks Davis switch (msg->header.typecookie) {
40094408d94SBrooks Davis case NGM_GIF_COOKIE:
40194408d94SBrooks Davis switch (msg->header.cmd) {
40294408d94SBrooks Davis case NGM_GIF_GET_IFNAME:
403bbb75d78SRuslan Ermilov NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
40494408d94SBrooks Davis if (resp == NULL) {
40594408d94SBrooks Davis error = ENOMEM;
40694408d94SBrooks Davis break;
40794408d94SBrooks Davis }
408bbb75d78SRuslan Ermilov strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
40994408d94SBrooks Davis break;
41094408d94SBrooks Davis case NGM_GIF_GET_IFINDEX:
41194408d94SBrooks Davis NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
41294408d94SBrooks Davis if (resp == NULL) {
41394408d94SBrooks Davis error = ENOMEM;
41494408d94SBrooks Davis break;
41594408d94SBrooks Davis }
41694408d94SBrooks Davis *((u_int32_t *)resp->data) = priv->ifp->if_index;
41794408d94SBrooks Davis break;
41894408d94SBrooks Davis default:
41994408d94SBrooks Davis error = EINVAL;
42094408d94SBrooks Davis break;
42194408d94SBrooks Davis }
42294408d94SBrooks Davis break;
42394408d94SBrooks Davis default:
42494408d94SBrooks Davis error = EINVAL;
42594408d94SBrooks Davis break;
42694408d94SBrooks Davis }
42794408d94SBrooks Davis NG_RESPOND_MSG(error, node, item, resp);
42894408d94SBrooks Davis NG_FREE_MSG(msg);
42994408d94SBrooks Davis return (error);
43094408d94SBrooks Davis }
43194408d94SBrooks Davis
43294408d94SBrooks Davis /*
43394408d94SBrooks Davis * Receive data on a hook.
43494408d94SBrooks Davis */
43594408d94SBrooks Davis static int
ng_gif_rcvdata(hook_p hook,item_p item)43694408d94SBrooks Davis ng_gif_rcvdata(hook_p hook, item_p item)
43794408d94SBrooks Davis {
43894408d94SBrooks Davis const node_p node = NG_HOOK_NODE(hook);
43994408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
44094408d94SBrooks Davis struct mbuf *m;
44194408d94SBrooks Davis
44294408d94SBrooks Davis NGI_GET_M(item, m);
44394408d94SBrooks Davis NG_FREE_ITEM(item);
4443ca24c28SJulian Elischer
44594408d94SBrooks Davis if (hook == priv->lower)
4463ca24c28SJulian Elischer return ng_gif_rcv_lower(node, m);
4476e551fb6SDavid E. O'Brien panic("%s: weird hook", __func__);
44894408d94SBrooks Davis }
44994408d94SBrooks Davis
45094408d94SBrooks Davis /*
45194408d94SBrooks Davis * Handle an mbuf received on the "lower" hook.
45294408d94SBrooks Davis */
45394408d94SBrooks Davis static int
ng_gif_rcv_lower(node_p node,struct mbuf * m)4543ca24c28SJulian Elischer ng_gif_rcv_lower(node_p node, struct mbuf *m)
45594408d94SBrooks Davis {
45694408d94SBrooks Davis struct sockaddr dst;
45794408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
45894408d94SBrooks Davis
45994408d94SBrooks Davis bzero(&dst, sizeof(dst));
46094408d94SBrooks Davis
46194408d94SBrooks Davis /* Make sure header is fully pulled up */
46294408d94SBrooks Davis if (m->m_pkthdr.len < sizeof(sa_family_t)) {
46394408d94SBrooks Davis NG_FREE_M(m);
46494408d94SBrooks Davis return (EINVAL);
46594408d94SBrooks Davis }
46694408d94SBrooks Davis if (m->m_len < sizeof(sa_family_t)
46794408d94SBrooks Davis && (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {
46894408d94SBrooks Davis return (ENOBUFS);
46994408d94SBrooks Davis }
47094408d94SBrooks Davis
47194408d94SBrooks Davis dst.sa_family = *mtod(m, sa_family_t *);
47294408d94SBrooks Davis m_adj(m, sizeof(sa_family_t));
47394408d94SBrooks Davis
47494408d94SBrooks Davis /* Send it on its way */
47594408d94SBrooks Davis /*
47694408d94SBrooks Davis * XXX: gif_output only uses dst for the family and passes the
47794408d94SBrooks Davis * fourth argument (rt) to in{,6}_gif_output which ignore it.
47894408d94SBrooks Davis * If this changes ng_gif will probably break.
47994408d94SBrooks Davis */
48094408d94SBrooks Davis return gif_output(priv->ifp, m, &dst, NULL);
48194408d94SBrooks Davis }
48294408d94SBrooks Davis
48394408d94SBrooks Davis /*
48494408d94SBrooks Davis * Shutdown node. This resets the node but does not remove it
48594408d94SBrooks Davis * unless the REALLY_DIE flag is set.
48694408d94SBrooks Davis */
48794408d94SBrooks Davis static int
ng_gif_shutdown(node_p node)48894408d94SBrooks Davis ng_gif_shutdown(node_p node)
48994408d94SBrooks Davis {
49094408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(node);
49194408d94SBrooks Davis
492be4252b3SJulian Elischer if (node->nd_flags & NGF_REALLY_DIE) {
49394408d94SBrooks Davis /*
49494408d94SBrooks Davis * WE came here because the gif interface is being destroyed,
495053359b7SPedro F. Giffuni * so stop being persistent.
49694408d94SBrooks Davis * Actually undo all the things we did on creation.
49794408d94SBrooks Davis * Assume the ifp has already been freed.
49894408d94SBrooks Davis */
49994408d94SBrooks Davis NG_NODE_SET_PRIVATE(node, NULL);
5001ede983cSDag-Erling Smørgrav free(priv, M_NETGRAPH);
50194408d94SBrooks Davis NG_NODE_UNREF(node); /* free node itself */
50294408d94SBrooks Davis return (0);
50394408d94SBrooks Davis }
504be4252b3SJulian Elischer NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */
50594408d94SBrooks Davis return (0);
50694408d94SBrooks Davis }
50794408d94SBrooks Davis
50894408d94SBrooks Davis /*
50994408d94SBrooks Davis * Hook disconnection.
51094408d94SBrooks Davis */
51194408d94SBrooks Davis static int
ng_gif_disconnect(hook_p hook)51294408d94SBrooks Davis ng_gif_disconnect(hook_p hook)
51394408d94SBrooks Davis {
51494408d94SBrooks Davis const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
51594408d94SBrooks Davis
51694408d94SBrooks Davis if (hook == priv->lower) {
51794408d94SBrooks Davis priv->lower = NULL;
51894408d94SBrooks Davis priv->lowerOrphan = 0;
51994408d94SBrooks Davis } else
5206e551fb6SDavid E. O'Brien panic("%s: weird hook", __func__);
52194408d94SBrooks Davis if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
52294408d94SBrooks Davis && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
52394408d94SBrooks Davis ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */
52494408d94SBrooks Davis
52594408d94SBrooks Davis return (0);
52694408d94SBrooks Davis }
52794408d94SBrooks Davis
52894408d94SBrooks Davis /******************************************************************
52994408d94SBrooks Davis INITIALIZATION
53094408d94SBrooks Davis ******************************************************************/
53194408d94SBrooks Davis
53294408d94SBrooks Davis /*
53394408d94SBrooks Davis * Handle loading and unloading for this node type.
53494408d94SBrooks Davis */
53594408d94SBrooks Davis static int
ng_gif_mod_event(module_t mod,int event,void * data)53694408d94SBrooks Davis ng_gif_mod_event(module_t mod, int event, void *data)
53794408d94SBrooks Davis {
5388b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter);
53994408d94SBrooks Davis struct ifnet *ifp;
54094408d94SBrooks Davis int error = 0;
54194408d94SBrooks Davis
54294408d94SBrooks Davis switch (event) {
54394408d94SBrooks Davis case MOD_LOAD:
54494408d94SBrooks Davis
54594408d94SBrooks Davis /* Register function hooks */
54694408d94SBrooks Davis if (ng_gif_attach_p != NULL) {
54794408d94SBrooks Davis error = EEXIST;
54894408d94SBrooks Davis break;
54994408d94SBrooks Davis }
55094408d94SBrooks Davis ng_gif_attach_p = ng_gif_attach;
55194408d94SBrooks Davis ng_gif_detach_p = ng_gif_detach;
55294408d94SBrooks Davis ng_gif_input_p = ng_gif_input;
55394408d94SBrooks Davis ng_gif_input_orphan_p = ng_gif_input_orphan;
55494408d94SBrooks Davis
55594408d94SBrooks Davis /* Create nodes for any already-existing gif interfaces */
55677dfcdc4SRobert Watson VNET_LIST_RLOCK();
557b30a244cSJeffrey Hsu IFNET_RLOCK();
5588b615593SMarko Zec VNET_FOREACH(vnet_iter) {
5598b615593SMarko Zec CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */
5604560b78dSJohn Baldwin CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
56194408d94SBrooks Davis if (ifp->if_type == IFT_GIF)
56294408d94SBrooks Davis ng_gif_attach(ifp);
56394408d94SBrooks Davis }
5648b615593SMarko Zec CURVNET_RESTORE();
5658b615593SMarko Zec }
566b30a244cSJeffrey Hsu IFNET_RUNLOCK();
56777dfcdc4SRobert Watson VNET_LIST_RUNLOCK();
56894408d94SBrooks Davis break;
56994408d94SBrooks Davis
57094408d94SBrooks Davis case MOD_UNLOAD:
57194408d94SBrooks Davis
57294408d94SBrooks Davis /*
57394408d94SBrooks Davis * Note that the base code won't try to unload us until
57494408d94SBrooks Davis * all nodes have been removed, and that can't happen
57594408d94SBrooks Davis * until all gif interfaces are destroyed. In any
57694408d94SBrooks Davis * case, we know there are no nodes left if the action
57794408d94SBrooks Davis * is MOD_UNLOAD, so there's no need to detach any nodes.
57894408d94SBrooks Davis *
57994408d94SBrooks Davis * XXX: what about manual unloads?!?
58094408d94SBrooks Davis */
58194408d94SBrooks Davis
58294408d94SBrooks Davis /* Unregister function hooks */
58394408d94SBrooks Davis ng_gif_attach_p = NULL;
58494408d94SBrooks Davis ng_gif_detach_p = NULL;
58594408d94SBrooks Davis ng_gif_input_p = NULL;
58694408d94SBrooks Davis ng_gif_input_orphan_p = NULL;
58794408d94SBrooks Davis break;
58894408d94SBrooks Davis
58994408d94SBrooks Davis default:
59094408d94SBrooks Davis error = EOPNOTSUPP;
59194408d94SBrooks Davis break;
59294408d94SBrooks Davis }
59394408d94SBrooks Davis return (error);
59494408d94SBrooks Davis }
595