/*1* ng_gif.c2*/34/*-5* SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause6*7* Copyright 2001 The Aerospace Corporation. All rights reserved.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12*13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions, and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions, and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18* 3. The name of The Aerospace Corporation may not be used to endorse or19* promote products derived from this software.20*21* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*33*34* Copyright (c) 1996-2000 Whistle Communications, Inc.35* All rights reserved.36*37* Subject to the following obligations and disclaimer of warranty, use and38* redistribution of this software, in source or object code forms, with or39* without modifications are expressly permitted by Whistle Communications;40* provided, however, that:41* 1. Any and all reproductions of the source or object code must include the42* copyright notice above and the following disclaimer of warranties; and43* 2. No rights are granted, in any manner or form, to use Whistle44* Communications, Inc. trademarks, including the mark "WHISTLE45* COMMUNICATIONS" on advertising, endorsements, or otherwise except as46* such appears in the above copyright notice or in the software.47*48* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND49* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO50* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,51* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF52* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.53* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY54* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS55* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.56* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES57* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING58* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,59* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR60* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY61* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT62* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF63* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY64* OF SUCH DAMAGE.65*/6667/*68* ng_gif(4) netgraph node type69*/70#include <sys/param.h>71#include <sys/systm.h>72#include <sys/kernel.h>73#include <sys/malloc.h>74#include <sys/mbuf.h>75#include <sys/errno.h>76#include <sys/syslog.h>77#include <sys/socket.h>7879#include <net/if.h>80#include <net/route.h>81#include <net/if_types.h>82#include <net/if_var.h>83#include <net/if_gif.h>84#include <net/if_private.h>85#include <net/vnet.h>8687#include <netgraph/ng_message.h>88#include <netgraph/netgraph.h>89#include <netgraph/ng_parse.h>90#include <netgraph/ng_gif.h>9192#define IFP2NG(ifp) ((struct ng_node *)((struct gif_softc *)(ifp->if_softc))->gif_netgraph)93#define IFP2NG_SET(ifp, val) (((struct gif_softc *)(ifp->if_softc))->gif_netgraph = (val))9495/* Per-node private data */96struct private {97struct ifnet *ifp; /* associated interface */98hook_p lower; /* lower OR orphan hook connection */99u_char lowerOrphan; /* whether lower is lower or orphan */100};101typedef struct private *priv_p;102103/* Functional hooks called from if_gif.c */104static void ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af);105static void ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af);106static void ng_gif_attach(struct ifnet *ifp);107static void ng_gif_detach(struct ifnet *ifp);108109/* Other functions */110static void ng_gif_input2(node_p node, struct mbuf **mp, int af);111static int ng_gif_glue_af(struct mbuf **mp, int af);112static int ng_gif_rcv_lower(node_p node, struct mbuf *m);113114/* Netgraph node methods */115static ng_constructor_t ng_gif_constructor;116static ng_rcvmsg_t ng_gif_rcvmsg;117static ng_shutdown_t ng_gif_shutdown;118static ng_newhook_t ng_gif_newhook;119static ng_connect_t ng_gif_connect;120static ng_rcvdata_t ng_gif_rcvdata;121static ng_disconnect_t ng_gif_disconnect;122static int ng_gif_mod_event(module_t mod, int event, void *data);123124/* List of commands and how to convert arguments to/from ASCII */125static const struct ng_cmdlist ng_gif_cmdlist[] = {126{127NGM_GIF_COOKIE,128NGM_GIF_GET_IFNAME,129"getifname",130NULL,131&ng_parse_string_type132},133{134NGM_GIF_COOKIE,135NGM_GIF_GET_IFINDEX,136"getifindex",137NULL,138&ng_parse_int32_type139},140{ 0 }141};142143static struct ng_type ng_gif_typestruct = {144.version = NG_ABI_VERSION,145.name = NG_GIF_NODE_TYPE,146.mod_event = ng_gif_mod_event,147.constructor = ng_gif_constructor,148.rcvmsg = ng_gif_rcvmsg,149.shutdown = ng_gif_shutdown,150.newhook = ng_gif_newhook,151.connect = ng_gif_connect,152.rcvdata = ng_gif_rcvdata,153.disconnect = ng_gif_disconnect,154.cmdlist = ng_gif_cmdlist,155};156MODULE_DEPEND(ng_gif, if_gif, 1,1,1);157NETGRAPH_INIT(gif, &ng_gif_typestruct);158159/******************************************************************160GIF FUNCTION HOOKS161******************************************************************/162163/*164* Handle a packet that has come in on an interface. We get to165* look at it here before any upper layer protocols do.166*/167static void168ng_gif_input(struct ifnet *ifp, struct mbuf **mp, int af)169{170const node_p node = IFP2NG(ifp);171const priv_p priv = NG_NODE_PRIVATE(node);172173/* If "lower" hook not connected, let packet continue */174if (priv->lower == NULL || priv->lowerOrphan)175return;176ng_gif_input2(node, mp, af);177}178179/*180* Handle a packet that has come in on an interface, and which181* does not match any of our known protocols (an ``orphan'').182*/183static void184ng_gif_input_orphan(struct ifnet *ifp, struct mbuf *m, int af)185{186const node_p node = IFP2NG(ifp);187const priv_p priv = NG_NODE_PRIVATE(node);188189/* If "orphan" hook not connected, let packet continue */190if (priv->lower == NULL || !priv->lowerOrphan) {191m_freem(m);192return;193}194ng_gif_input2(node, &m, af);195if (m != NULL)196m_freem(m);197}198199/*200* Handle a packet that has come in on a gif interface.201* Attach the address family to the mbuf for later use.202*/203static void204ng_gif_input2(node_p node, struct mbuf **mp, int af)205{206const priv_p priv = NG_NODE_PRIVATE(node);207int error;208209/* Glue address family on */210if ((error = ng_gif_glue_af(mp, af)) != 0)211return;212213/* Send out lower/orphan hook */214NG_SEND_DATA_ONLY(error, priv->lower, *mp);215*mp = NULL;216}217218/*219* A new gif interface has been attached.220* Create a new node for it, etc.221*/222static void223ng_gif_attach(struct ifnet *ifp)224{225priv_p priv;226node_p node;227228/* Create node */229KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));230if (ng_make_node_common(&ng_gif_typestruct, &node) != 0) {231log(LOG_ERR, "%s: can't %s for %s\n",232__func__, "create node", ifp->if_xname);233return;234}235236/* Allocate private data */237priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);238if (priv == NULL) {239log(LOG_ERR, "%s: can't %s for %s\n",240__func__, "allocate memory", ifp->if_xname);241NG_NODE_UNREF(node);242return;243}244NG_NODE_SET_PRIVATE(node, priv);245priv->ifp = ifp;246IFP2NG_SET(ifp, node);247248/* Try to give the node the same name as the interface */249if (ng_name_node(node, ifp->if_xname) != 0) {250log(LOG_WARNING, "%s: can't name node %s\n",251__func__, ifp->if_xname);252}253}254255/*256* An interface is being detached.257* REALLY Destroy its node.258*/259static void260ng_gif_detach(struct ifnet *ifp)261{262const node_p node = IFP2NG(ifp);263priv_p priv;264265if (node == NULL) /* no node (why not?), ignore */266return;267priv = NG_NODE_PRIVATE(node);268NG_NODE_REALLY_DIE(node); /* Force real removal of node */269/*270* We can't assume the ifnet is still around when we run shutdown271* So zap it now. XXX We HOPE that anything running at this time272* handles it (as it should in the non netgraph case).273*/274IFP2NG_SET(ifp, NULL);275priv->ifp = NULL; /* XXX race if interrupted an output packet */276ng_rmnode_self(node); /* remove all netgraph parts */277}278279/*280* Optimization for gluing the address family onto281* the front of an incoming packet.282*/283static int284ng_gif_glue_af(struct mbuf **mp, int af)285{286struct mbuf *m = *mp;287int error = 0;288sa_family_t tmp_af;289290tmp_af = (sa_family_t) af;291292/*293* XXX: should try to bring back some of the optimizations from294* ng_ether.c295*/296297/*298* Doing anything more is likely to get more299* expensive than it's worth..300* it's probable that everything else is in one301* big lump. The next node will do an m_pullup()302* for exactly the amount of data it needs and303* hopefully everything after that will not304* need one. So let's just use M_PREPEND.305*/306M_PREPEND(m, sizeof (tmp_af), M_NOWAIT);307if (m == NULL) {308error = ENOBUFS;309goto done;310}311312#if 0313copy:314#endif315/* Copy header and return (possibly new) mbuf */316*mtod(m, sa_family_t *) = tmp_af;317#if 0318bcopy((caddr_t)&tmp_af, mtod(m, sa_family_t *), sizeof(tmp_af));319#endif320done:321*mp = m;322return error;323}324325/******************************************************************326NETGRAPH NODE METHODS327******************************************************************/328329/*330* It is not possible or allowable to create a node of this type.331* Nodes get created when the interface is attached (or, when332* this node type's KLD is loaded).333*/334static int335ng_gif_constructor(node_p node)336{337return (EINVAL);338}339340/*341* Check for attaching a new hook.342*/343static int344ng_gif_newhook(node_p node, hook_p hook, const char *name)345{346const priv_p priv = NG_NODE_PRIVATE(node);347u_char orphan = priv->lowerOrphan;348hook_p *hookptr;349350/* Divert hook is an alias for lower */351if (strcmp(name, NG_GIF_HOOK_DIVERT) == 0)352name = NG_GIF_HOOK_LOWER;353354/* Which hook? */355if (strcmp(name, NG_GIF_HOOK_LOWER) == 0) {356hookptr = &priv->lower;357orphan = 0;358} else if (strcmp(name, NG_GIF_HOOK_ORPHAN) == 0) {359hookptr = &priv->lower;360orphan = 1;361} else362return (EINVAL);363364/* Check if already connected (shouldn't be, but doesn't hurt) */365if (*hookptr != NULL)366return (EISCONN);367368/* OK */369*hookptr = hook;370priv->lowerOrphan = orphan;371return (0);372}373374/*375* Hooks are attached, adjust to force queueing.376* We don't really care which hook it is.377* they should all be queuing for outgoing data.378*/379static int380ng_gif_connect(hook_p hook)381{382NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));383return (0);384}385386/*387* Receive an incoming control message.388*/389static int390ng_gif_rcvmsg(node_p node, item_p item, hook_p lasthook)391{392const priv_p priv = NG_NODE_PRIVATE(node);393struct ng_mesg *resp = NULL;394int error = 0;395struct ng_mesg *msg;396397NGI_GET_MSG(item, msg);398switch (msg->header.typecookie) {399case NGM_GIF_COOKIE:400switch (msg->header.cmd) {401case NGM_GIF_GET_IFNAME:402NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);403if (resp == NULL) {404error = ENOMEM;405break;406}407strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);408break;409case NGM_GIF_GET_IFINDEX:410NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);411if (resp == NULL) {412error = ENOMEM;413break;414}415*((u_int32_t *)resp->data) = priv->ifp->if_index;416break;417default:418error = EINVAL;419break;420}421break;422default:423error = EINVAL;424break;425}426NG_RESPOND_MSG(error, node, item, resp);427NG_FREE_MSG(msg);428return (error);429}430431/*432* Receive data on a hook.433*/434static int435ng_gif_rcvdata(hook_p hook, item_p item)436{437const node_p node = NG_HOOK_NODE(hook);438const priv_p priv = NG_NODE_PRIVATE(node);439struct mbuf *m;440441NGI_GET_M(item, m);442NG_FREE_ITEM(item);443444if (hook == priv->lower)445return ng_gif_rcv_lower(node, m);446panic("%s: weird hook", __func__);447}448449/*450* Handle an mbuf received on the "lower" hook.451*/452static int453ng_gif_rcv_lower(node_p node, struct mbuf *m)454{455struct sockaddr dst;456const priv_p priv = NG_NODE_PRIVATE(node);457458bzero(&dst, sizeof(dst));459460/* Make sure header is fully pulled up */461if (m->m_pkthdr.len < sizeof(sa_family_t)) {462NG_FREE_M(m);463return (EINVAL);464}465if (m->m_len < sizeof(sa_family_t)466&& (m = m_pullup(m, sizeof(sa_family_t))) == NULL) {467return (ENOBUFS);468}469470dst.sa_family = *mtod(m, sa_family_t *);471m_adj(m, sizeof(sa_family_t));472473/* Send it on its way */474/*475* XXX: gif_output only uses dst for the family and passes the476* fourth argument (rt) to in{,6}_gif_output which ignore it.477* If this changes ng_gif will probably break.478*/479return gif_output(priv->ifp, m, &dst, NULL);480}481482/*483* Shutdown node. This resets the node but does not remove it484* unless the REALLY_DIE flag is set.485*/486static int487ng_gif_shutdown(node_p node)488{489const priv_p priv = NG_NODE_PRIVATE(node);490491if (node->nd_flags & NGF_REALLY_DIE) {492/*493* WE came here because the gif interface is being destroyed,494* so stop being persistent.495* Actually undo all the things we did on creation.496* Assume the ifp has already been freed.497*/498NG_NODE_SET_PRIVATE(node, NULL);499free(priv, M_NETGRAPH);500NG_NODE_UNREF(node); /* free node itself */501return (0);502}503NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */504return (0);505}506507/*508* Hook disconnection.509*/510static int511ng_gif_disconnect(hook_p hook)512{513const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));514515if (hook == priv->lower) {516priv->lower = NULL;517priv->lowerOrphan = 0;518} else519panic("%s: weird hook", __func__);520if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)521&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))522ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */523524return (0);525}526527/******************************************************************528INITIALIZATION529******************************************************************/530531/*532* Handle loading and unloading for this node type.533*/534static int535ng_gif_mod_event(module_t mod, int event, void *data)536{537VNET_ITERATOR_DECL(vnet_iter);538struct ifnet *ifp;539int error = 0;540541switch (event) {542case MOD_LOAD:543544/* Register function hooks */545if (ng_gif_attach_p != NULL) {546error = EEXIST;547break;548}549ng_gif_attach_p = ng_gif_attach;550ng_gif_detach_p = ng_gif_detach;551ng_gif_input_p = ng_gif_input;552ng_gif_input_orphan_p = ng_gif_input_orphan;553554/* Create nodes for any already-existing gif interfaces */555VNET_LIST_RLOCK();556IFNET_RLOCK();557VNET_FOREACH(vnet_iter) {558CURVNET_SET_QUIET(vnet_iter); /* XXX revisit quiet */559CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {560if (ifp->if_type == IFT_GIF)561ng_gif_attach(ifp);562}563CURVNET_RESTORE();564}565IFNET_RUNLOCK();566VNET_LIST_RUNLOCK();567break;568569case MOD_UNLOAD:570571/*572* Note that the base code won't try to unload us until573* all nodes have been removed, and that can't happen574* until all gif interfaces are destroyed. In any575* case, we know there are no nodes left if the action576* is MOD_UNLOAD, so there's no need to detach any nodes.577*578* XXX: what about manual unloads?!?579*/580581/* Unregister function hooks */582ng_gif_attach_p = NULL;583ng_gif_detach_p = NULL;584ng_gif_input_p = NULL;585ng_gif_input_orphan_p = NULL;586break;587588default:589error = EOPNOTSUPP;590break;591}592return (error);593}594595596