The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_iface.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * ng_iface.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    7  * All rights reserved.
    8  * 
    9  * Subject to the following obligations and disclaimer of warranty, use and
   10  * redistribution of this software, in source or object code forms, with or
   11  * without modifications are expressly permitted by Whistle Communications;
   12  * provided, however, that:
   13  * 1. Any and all reproductions of the source or object code must include the
   14  *    copyright notice above and the following disclaimer of warranties; and
   15  * 2. No rights are granted, in any manner or form, to use Whistle
   16  *    Communications, Inc. trademarks, including the mark "WHISTLE
   17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   18  *    such appears in the above copyright notice or in the software.
   19  * 
   20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   36  * OF SUCH DAMAGE.
   37  *
   38  * Author: Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $FreeBSD$
   41  * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
   42  */
   43 
   44 /*
   45  * This node is also a system networking interface. It has
   46  * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
   47  * are simply relayed between the interface and the hooks.
   48  *
   49  * Interfaces are named ng0, ng1, etc.  New nodes take the
   50  * first available interface name.
   51  *
   52  * This node also includes Berkeley packet filter support.
   53  */
   54 
   55 #include "opt_atalk.h"
   56 #include "opt_inet.h"
   57 #include "opt_inet6.h"
   58 #include "opt_ipx.h"
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/errno.h>
   63 #include <sys/kernel.h>
   64 #include <sys/lock.h>
   65 #include <sys/malloc.h>
   66 #include <sys/mbuf.h>
   67 #include <sys/errno.h>
   68 #include <sys/proc.h>
   69 #include <sys/random.h>
   70 #include <sys/rmlock.h>
   71 #include <sys/sockio.h>
   72 #include <sys/socket.h>
   73 #include <sys/syslog.h>
   74 #include <sys/libkern.h>
   75 
   76 #include <net/if.h>
   77 #include <net/if_types.h>
   78 #include <net/bpf.h>
   79 #include <net/netisr.h>
   80 #include <net/route.h>
   81 #include <net/vnet.h>
   82 
   83 #include <netinet/in.h>
   84 
   85 #include <netgraph/ng_message.h>
   86 #include <netgraph/netgraph.h>
   87 #include <netgraph/ng_parse.h>
   88 #include <netgraph/ng_iface.h>
   89 #include <netgraph/ng_cisco.h>
   90 
   91 #ifdef NG_SEPARATE_MALLOC
   92 static MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node");
   93 #else
   94 #define M_NETGRAPH_IFACE M_NETGRAPH
   95 #endif
   96 
   97 /* This struct describes one address family */
   98 struct iffam {
   99         sa_family_t     family;         /* Address family */
  100         const char      *hookname;      /* Name for hook */
  101 };
  102 typedef const struct iffam *iffam_p;
  103 
  104 /* List of address families supported by our interface */
  105 const static struct iffam gFamilies[] = {
  106         { AF_INET,      NG_IFACE_HOOK_INET      },
  107         { AF_INET6,     NG_IFACE_HOOK_INET6     },
  108         { AF_APPLETALK, NG_IFACE_HOOK_ATALK     },
  109         { AF_IPX,       NG_IFACE_HOOK_IPX       },
  110         { AF_ATM,       NG_IFACE_HOOK_ATM       },
  111         { AF_NATM,      NG_IFACE_HOOK_NATM      },
  112 };
  113 #define NUM_FAMILIES            (sizeof(gFamilies) / sizeof(*gFamilies))
  114 
  115 /* Node private data */
  116 struct ng_iface_private {
  117         struct  ifnet *ifp;             /* Our interface */
  118         int     unit;                   /* Interface unit number */
  119         node_p  node;                   /* Our netgraph node */
  120         hook_p  hooks[NUM_FAMILIES];    /* Hook for each address family */
  121         struct rmlock   lock;           /* Protect private data changes */
  122 };
  123 typedef struct ng_iface_private *priv_p;
  124 
  125 #define PRIV_RLOCK(priv, t)     rm_rlock(&priv->lock, t)
  126 #define PRIV_RUNLOCK(priv, t)   rm_runlock(&priv->lock, t)
  127 #define PRIV_WLOCK(priv)        rm_wlock(&priv->lock)
  128 #define PRIV_WUNLOCK(priv)      rm_wunlock(&priv->lock)
  129 
  130 /* Interface methods */
  131 static void     ng_iface_start(struct ifnet *ifp);
  132 static int      ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
  133 static int      ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
  134                         const struct sockaddr *dst, struct route *ro);
  135 static void     ng_iface_bpftap(struct ifnet *ifp,
  136                         struct mbuf *m, sa_family_t family);
  137 static int      ng_iface_send(struct ifnet *ifp, struct mbuf *m,
  138                         sa_family_t sa);
  139 #ifdef DEBUG
  140 static void     ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
  141 #endif
  142 
  143 /* Netgraph methods */
  144 static int              ng_iface_mod_event(module_t, int, void *);
  145 static ng_constructor_t ng_iface_constructor;
  146 static ng_rcvmsg_t      ng_iface_rcvmsg;
  147 static ng_shutdown_t    ng_iface_shutdown;
  148 static ng_newhook_t     ng_iface_newhook;
  149 static ng_rcvdata_t     ng_iface_rcvdata;
  150 static ng_disconnect_t  ng_iface_disconnect;
  151 
  152 /* Helper stuff */
  153 static iffam_p  get_iffam_from_af(sa_family_t family);
  154 static iffam_p  get_iffam_from_hook(priv_p priv, hook_p hook);
  155 static iffam_p  get_iffam_from_name(const char *name);
  156 static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
  157 
  158 /* Parse type for struct ng_cisco_ipaddr */
  159 static const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
  160         = NG_CISCO_IPADDR_TYPE_INFO;
  161 static const struct ng_parse_type ng_cisco_ipaddr_type = {
  162         &ng_parse_struct_type,
  163         &ng_cisco_ipaddr_type_fields
  164 };
  165 
  166 /* List of commands and how to convert arguments to/from ASCII */
  167 static const struct ng_cmdlist ng_iface_cmds[] = {
  168         {
  169           NGM_IFACE_COOKIE,
  170           NGM_IFACE_GET_IFNAME,
  171           "getifname",
  172           NULL,
  173           &ng_parse_string_type
  174         },
  175         {
  176           NGM_IFACE_COOKIE,
  177           NGM_IFACE_POINT2POINT,
  178           "point2point",
  179           NULL,
  180           NULL
  181         },
  182         {
  183           NGM_IFACE_COOKIE,
  184           NGM_IFACE_BROADCAST,
  185           "broadcast",
  186           NULL,
  187           NULL
  188         },
  189         {
  190           NGM_CISCO_COOKIE,
  191           NGM_CISCO_GET_IPADDR,
  192           "getipaddr",
  193           NULL,
  194           &ng_cisco_ipaddr_type
  195         },
  196         {
  197           NGM_IFACE_COOKIE,
  198           NGM_IFACE_GET_IFINDEX,
  199           "getifindex",
  200           NULL,
  201           &ng_parse_uint32_type
  202         },
  203         { 0 }
  204 };
  205 
  206 /* Node type descriptor */
  207 static struct ng_type typestruct = {
  208         .version =      NG_ABI_VERSION,
  209         .name =         NG_IFACE_NODE_TYPE,
  210         .mod_event =    ng_iface_mod_event,
  211         .constructor =  ng_iface_constructor,
  212         .rcvmsg =       ng_iface_rcvmsg,
  213         .shutdown =     ng_iface_shutdown,
  214         .newhook =      ng_iface_newhook,
  215         .rcvdata =      ng_iface_rcvdata,
  216         .disconnect =   ng_iface_disconnect,
  217         .cmdlist =      ng_iface_cmds,
  218 };
  219 NETGRAPH_INIT(iface, &typestruct);
  220 
  221 static VNET_DEFINE(struct unrhdr *, ng_iface_unit);
  222 #define V_ng_iface_unit                 VNET(ng_iface_unit)
  223 
  224 /************************************************************************
  225                         HELPER STUFF
  226  ************************************************************************/
  227 
  228 /*
  229  * Get the family descriptor from the family ID
  230  */
  231 static __inline iffam_p
  232 get_iffam_from_af(sa_family_t family)
  233 {
  234         iffam_p iffam;
  235         int k;
  236 
  237         for (k = 0; k < NUM_FAMILIES; k++) {
  238                 iffam = &gFamilies[k];
  239                 if (iffam->family == family)
  240                         return (iffam);
  241         }
  242         return (NULL);
  243 }
  244 
  245 /*
  246  * Get the family descriptor from the hook
  247  */
  248 static __inline iffam_p
  249 get_iffam_from_hook(priv_p priv, hook_p hook)
  250 {
  251         int k;
  252 
  253         for (k = 0; k < NUM_FAMILIES; k++)
  254                 if (priv->hooks[k] == hook)
  255                         return (&gFamilies[k]);
  256         return (NULL);
  257 }
  258 
  259 /*
  260  * Get the hook from the iffam descriptor
  261  */
  262 
  263 static __inline hook_p *
  264 get_hook_from_iffam(priv_p priv, iffam_p iffam)
  265 {
  266         return (&priv->hooks[iffam - gFamilies]);
  267 }
  268 
  269 /*
  270  * Get the iffam descriptor from the name
  271  */
  272 static __inline iffam_p
  273 get_iffam_from_name(const char *name)
  274 {
  275         iffam_p iffam;
  276         int k;
  277 
  278         for (k = 0; k < NUM_FAMILIES; k++) {
  279                 iffam = &gFamilies[k];
  280                 if (!strcmp(iffam->hookname, name))
  281                         return (iffam);
  282         }
  283         return (NULL);
  284 }
  285 
  286 /************************************************************************
  287                         INTERFACE STUFF
  288  ************************************************************************/
  289 
  290 /*
  291  * Process an ioctl for the virtual interface
  292  */
  293 static int
  294 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  295 {
  296         struct ifreq *const ifr = (struct ifreq *) data;
  297         int error = 0;
  298 
  299 #ifdef DEBUG
  300         ng_iface_print_ioctl(ifp, command, data);
  301 #endif
  302         switch (command) {
  303 
  304         /* These two are mostly handled at a higher layer */
  305         case SIOCSIFADDR:
  306                 ifp->if_flags |= IFF_UP;
  307                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  308                 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
  309                 break;
  310         case SIOCGIFADDR:
  311                 break;
  312 
  313         /* Set flags */
  314         case SIOCSIFFLAGS:
  315                 /*
  316                  * If the interface is marked up and stopped, then start it.
  317                  * If it is marked down and running, then stop it.
  318                  */
  319                 if (ifr->ifr_flags & IFF_UP) {
  320                         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
  321                                 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
  322                                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  323                         }
  324                 } else {
  325                         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
  326                                 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING |
  327                                     IFF_DRV_OACTIVE);
  328                 }
  329                 break;
  330 
  331         /* Set the interface MTU */
  332         case SIOCSIFMTU:
  333                 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
  334                     || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
  335                         error = EINVAL;
  336                 else
  337                         ifp->if_mtu = ifr->ifr_mtu;
  338                 break;
  339 
  340         /* Stuff that's not supported */
  341         case SIOCADDMULTI:
  342         case SIOCDELMULTI:
  343                 error = 0;
  344                 break;
  345         case SIOCSIFPHYS:
  346                 error = EOPNOTSUPP;
  347                 break;
  348 
  349         default:
  350                 error = EINVAL;
  351                 break;
  352         }
  353         return (error);
  354 }
  355 
  356 /*
  357  * This routine is called to deliver a packet out the interface.
  358  * We simply look at the address family and relay the packet to
  359  * the corresponding hook, if it exists and is connected.
  360  */
  361 
  362 static int
  363 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
  364         const struct sockaddr *dst, struct route *ro)
  365 {
  366         struct m_tag *mtag;
  367         uint32_t af;
  368         int error;
  369 
  370         /* Check interface flags */
  371         if (!((ifp->if_flags & IFF_UP) &&
  372             (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
  373                 m_freem(m);
  374                 return (ENETDOWN);
  375         }
  376 
  377         /* Protect from deadly infinite recursion. */
  378         mtag = NULL;
  379         while ((mtag = m_tag_locate(m, MTAG_NGIF, MTAG_NGIF_CALLED, mtag))) {
  380                 if (*(struct ifnet **)(mtag + 1) == ifp) {
  381                         log(LOG_NOTICE, "Loop detected on %s\n", ifp->if_xname);
  382                         m_freem(m);
  383                         return (EDEADLK);
  384                 }
  385         }
  386         mtag = m_tag_alloc(MTAG_NGIF, MTAG_NGIF_CALLED, sizeof(struct ifnet *),
  387             M_NOWAIT);
  388         if (mtag == NULL) {
  389                 m_freem(m);
  390                 return (ENOMEM);
  391         }
  392         *(struct ifnet **)(mtag + 1) = ifp;
  393         m_tag_prepend(m, mtag);
  394 
  395         /* BPF writes need to be handled specially. */
  396         if (dst->sa_family == AF_UNSPEC)
  397                 bcopy(dst->sa_data, &af, sizeof(af));
  398         else
  399                 af = dst->sa_family;
  400 
  401         /* Berkeley packet filter */
  402         ng_iface_bpftap(ifp, m, af);
  403 
  404         if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
  405                 M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT);
  406                 if (m == NULL) {
  407                         IFQ_LOCK(&ifp->if_snd);
  408                         IFQ_INC_DROPS(&ifp->if_snd);
  409                         IFQ_UNLOCK(&ifp->if_snd);
  410                         ifp->if_oerrors++;
  411                         return (ENOBUFS);
  412                 }
  413                 *(sa_family_t *)m->m_data = af;
  414                 error = (ifp->if_transmit)(ifp, m);
  415         } else
  416                 error = ng_iface_send(ifp, m, af);
  417 
  418         return (error);
  419 }
  420 
  421 /*
  422  * Start method is used only when ALTQ is enabled.
  423  */
  424 static void
  425 ng_iface_start(struct ifnet *ifp)
  426 {
  427         struct mbuf *m;
  428         sa_family_t sa;
  429 
  430         KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__));
  431 
  432         for(;;) {
  433                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
  434                 if (m == NULL)
  435                         break;
  436                 sa = *mtod(m, sa_family_t *);
  437                 m_adj(m, sizeof(sa_family_t));
  438                 ng_iface_send(ifp, m, sa);
  439         }
  440 }
  441 
  442 /*
  443  * Flash a packet by the BPF (requires prepending 4 byte AF header)
  444  * Note the phoney mbuf; this is OK because BPF treats it read-only.
  445  */
  446 static void
  447 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
  448 {
  449         KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
  450         if (bpf_peers_present(ifp->if_bpf)) {
  451                 int32_t family4 = (int32_t)family;
  452                 bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
  453         }
  454 }
  455 
  456 /*
  457  * This routine does actual delivery of the packet into the
  458  * netgraph(4). It is called from ng_iface_start() and
  459  * ng_iface_output().
  460  */
  461 static int
  462 ng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa)
  463 {
  464         struct rm_priotracker priv_tracker;
  465         const priv_p priv = (priv_p) ifp->if_softc;
  466         const iffam_p iffam = get_iffam_from_af(sa);
  467         hook_p hook;
  468         int error;
  469         int len;
  470 
  471         /* Check address family to determine hook (if known) */
  472         if (iffam == NULL) {
  473                 m_freem(m);
  474                 log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa);
  475                 return (EAFNOSUPPORT);
  476         }
  477 
  478         /* Copy length before the mbuf gets invalidated. */
  479         len = m->m_pkthdr.len;
  480 
  481         PRIV_RLOCK(priv, &priv_tracker);
  482         hook = *get_hook_from_iffam(priv, iffam);
  483         if (hook == NULL) {
  484                 NG_FREE_M(m);
  485                 PRIV_RUNLOCK(priv, &priv_tracker);
  486                 return ENETDOWN;
  487         }
  488         NG_HOOK_REF(hook);
  489         PRIV_RUNLOCK(priv, &priv_tracker);
  490 
  491         NG_OUTBOUND_THREAD_REF();
  492         NG_SEND_DATA_ONLY(error, hook, m);
  493         NG_OUTBOUND_THREAD_UNREF();
  494         NG_HOOK_UNREF(hook);
  495 
  496         /* Update stats. */
  497         if (error == 0) {
  498                 ifp->if_obytes += len;
  499                 ifp->if_opackets++;
  500         }
  501 
  502         return (error);
  503 }
  504 
  505 #ifdef DEBUG
  506 /*
  507  * Display an ioctl to the virtual interface
  508  */
  509 
  510 static void
  511 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
  512 {
  513         char   *str;
  514 
  515         switch (command & IOC_DIRMASK) {
  516         case IOC_VOID:
  517                 str = "IO";
  518                 break;
  519         case IOC_OUT:
  520                 str = "IOR";
  521                 break;
  522         case IOC_IN:
  523                 str = "IOW";
  524                 break;
  525         case IOC_INOUT:
  526                 str = "IORW";
  527                 break;
  528         default:
  529                 str = "IO??";
  530         }
  531         log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
  532                ifp->if_xname,
  533                str,
  534                IOCGROUP(command),
  535                command & 0xff,
  536                IOCPARM_LEN(command));
  537 }
  538 #endif /* DEBUG */
  539 
  540 /************************************************************************
  541                         NETGRAPH NODE STUFF
  542  ************************************************************************/
  543 
  544 /*
  545  * Constructor for a node
  546  */
  547 static int
  548 ng_iface_constructor(node_p node)
  549 {
  550         struct ifnet *ifp;
  551         priv_p priv;
  552 
  553         /* Allocate node and interface private structures */
  554         priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO);
  555         ifp = if_alloc(IFT_PROPVIRTUAL);
  556         if (ifp == NULL) {
  557                 free(priv, M_NETGRAPH_IFACE);
  558                 return (ENOMEM);
  559         }
  560 
  561         rm_init(&priv->lock, "ng_iface private rmlock");
  562 
  563         /* Link them together */
  564         ifp->if_softc = priv;
  565         priv->ifp = ifp;
  566 
  567         /* Get an interface unit number */
  568         priv->unit = alloc_unr(V_ng_iface_unit);
  569 
  570         /* Link together node and private info */
  571         NG_NODE_SET_PRIVATE(node, priv);
  572         priv->node = node;
  573 
  574         /* Initialize interface structure */
  575         if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
  576         ifp->if_output = ng_iface_output;
  577         ifp->if_start = ng_iface_start;
  578         ifp->if_ioctl = ng_iface_ioctl;
  579         ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
  580         ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
  581         ifp->if_type = IFT_PROPVIRTUAL;         /* XXX */
  582         ifp->if_addrlen = 0;                    /* XXX */
  583         ifp->if_hdrlen = 0;                     /* XXX */
  584         ifp->if_baudrate = 64000;               /* XXX */
  585         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  586         ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
  587         IFQ_SET_READY(&ifp->if_snd);
  588 
  589         /* Give this node the same name as the interface (if possible) */
  590         if (ng_name_node(node, ifp->if_xname) != 0)
  591                 log(LOG_WARNING, "%s: can't acquire netgraph name\n",
  592                     ifp->if_xname);
  593 
  594         /* Attach the interface */
  595         if_attach(ifp);
  596         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
  597 
  598         /* Done */
  599         return (0);
  600 }
  601 
  602 /*
  603  * Give our ok for a hook to be added
  604  */
  605 static int
  606 ng_iface_newhook(node_p node, hook_p hook, const char *name)
  607 {
  608         const iffam_p iffam = get_iffam_from_name(name);
  609         const priv_p priv = NG_NODE_PRIVATE(node);
  610         hook_p *hookptr;
  611 
  612         if (iffam == NULL)
  613                 return (EPFNOSUPPORT);
  614         PRIV_WLOCK(priv);
  615         hookptr = get_hook_from_iffam(priv, iffam);
  616         if (*hookptr != NULL) {
  617                 PRIV_WUNLOCK(priv);
  618                 return (EISCONN);
  619         }
  620         *hookptr = hook;
  621         NG_HOOK_HI_STACK(hook);
  622         NG_HOOK_SET_TO_INBOUND(hook);
  623         PRIV_WUNLOCK(priv);
  624         return (0);
  625 }
  626 
  627 /*
  628  * Receive a control message
  629  */
  630 static int
  631 ng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
  632 {
  633         const priv_p priv = NG_NODE_PRIVATE(node);
  634         struct ifnet *const ifp = priv->ifp;
  635         struct ng_mesg *resp = NULL;
  636         int error = 0;
  637         struct ng_mesg *msg;
  638 
  639         NGI_GET_MSG(item, msg);
  640         switch (msg->header.typecookie) {
  641         case NGM_IFACE_COOKIE:
  642                 switch (msg->header.cmd) {
  643                 case NGM_IFACE_GET_IFNAME:
  644                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
  645                         if (resp == NULL) {
  646                                 error = ENOMEM;
  647                                 break;
  648                         }
  649                         strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
  650                         break;
  651 
  652                 case NGM_IFACE_POINT2POINT:
  653                 case NGM_IFACE_BROADCAST:
  654                     {
  655 
  656                         /* Deny request if interface is UP */
  657                         if ((ifp->if_flags & IFF_UP) != 0)
  658                                 return (EBUSY);
  659 
  660                         /* Change flags */
  661                         switch (msg->header.cmd) {
  662                         case NGM_IFACE_POINT2POINT:
  663                                 ifp->if_flags |= IFF_POINTOPOINT;
  664                                 ifp->if_flags &= ~IFF_BROADCAST;
  665                                 break;
  666                         case NGM_IFACE_BROADCAST:
  667                                 ifp->if_flags &= ~IFF_POINTOPOINT;
  668                                 ifp->if_flags |= IFF_BROADCAST;
  669                                 break;
  670                         }
  671                         break;
  672                     }
  673 
  674                 case NGM_IFACE_GET_IFINDEX:
  675                         NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
  676                         if (resp == NULL) {
  677                                 error = ENOMEM;
  678                                 break;
  679                         }
  680                         *((uint32_t *)resp->data) = priv->ifp->if_index;
  681                         break;
  682 
  683                 default:
  684                         error = EINVAL;
  685                         break;
  686                 }
  687                 break;
  688         case NGM_CISCO_COOKIE:
  689                 switch (msg->header.cmd) {
  690                 case NGM_CISCO_GET_IPADDR:      /* we understand this too */
  691                     {
  692                         struct ifaddr *ifa;
  693 
  694                         /* Return the first configured IP address */
  695                         if_addr_rlock(ifp);
  696                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  697                                 struct ng_cisco_ipaddr *ips;
  698 
  699                                 if (ifa->ifa_addr->sa_family != AF_INET)
  700                                         continue;
  701                                 NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
  702                                 if (resp == NULL) {
  703                                         error = ENOMEM;
  704                                         break;
  705                                 }
  706                                 ips = (struct ng_cisco_ipaddr *)resp->data;
  707                                 ips->ipaddr = ((struct sockaddr_in *)
  708                                                 ifa->ifa_addr)->sin_addr;
  709                                 ips->netmask = ((struct sockaddr_in *)
  710                                                 ifa->ifa_netmask)->sin_addr;
  711                                 break;
  712                         }
  713                         if_addr_runlock(ifp);
  714 
  715                         /* No IP addresses on this interface? */
  716                         if (ifa == NULL)
  717                                 error = EADDRNOTAVAIL;
  718                         break;
  719                     }
  720                 default:
  721                         error = EINVAL;
  722                         break;
  723                 }
  724                 break;
  725         case NGM_FLOW_COOKIE:
  726                 switch (msg->header.cmd) {
  727                 case NGM_LINK_IS_UP:
  728                         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  729                         break;
  730                 case NGM_LINK_IS_DOWN:
  731                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  732                         break;
  733                 default:
  734                         break;
  735                 }
  736                 break;
  737         default:
  738                 error = EINVAL;
  739                 break;
  740         }
  741         NG_RESPOND_MSG(error, node, item, resp);
  742         NG_FREE_MSG(msg);
  743         return (error);
  744 }
  745 
  746 /*
  747  * Recive data from a hook. Pass the packet to the correct input routine.
  748  */
  749 static int
  750 ng_iface_rcvdata(hook_p hook, item_p item)
  751 {
  752         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  753         const iffam_p iffam = get_iffam_from_hook(priv, hook);
  754         struct ifnet *const ifp = priv->ifp;
  755         struct mbuf *m;
  756         int isr;
  757 
  758         NGI_GET_M(item, m);
  759         NG_FREE_ITEM(item);
  760         /* Sanity checks */
  761         KASSERT(iffam != NULL, ("%s: iffam", __func__));
  762         M_ASSERTPKTHDR(m);
  763         if ((ifp->if_flags & IFF_UP) == 0) {
  764                 NG_FREE_M(m);
  765                 return (ENETDOWN);
  766         }
  767 
  768         /* Update interface stats */
  769         ifp->if_ipackets++;
  770         ifp->if_ibytes += m->m_pkthdr.len;
  771 
  772         /* Note receiving interface */
  773         m->m_pkthdr.rcvif = ifp;
  774 
  775         /* Berkeley packet filter */
  776         ng_iface_bpftap(ifp, m, iffam->family);
  777 
  778         /* Send packet */
  779         switch (iffam->family) {
  780 #ifdef INET
  781         case AF_INET:
  782                 isr = NETISR_IP;
  783                 break;
  784 #endif
  785 #ifdef INET6
  786         case AF_INET6:
  787                 isr = NETISR_IPV6;
  788                 break;
  789 #endif
  790 #ifdef IPX
  791         case AF_IPX:
  792                 isr = NETISR_IPX;
  793                 break;
  794 #endif
  795 #ifdef NETATALK
  796         case AF_APPLETALK:
  797                 isr = NETISR_ATALK2;
  798                 break;
  799 #endif
  800         default:
  801                 m_freem(m);
  802                 return (EAFNOSUPPORT);
  803         }
  804         if (harvest.point_to_point)
  805                 random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
  806         M_SETFIB(m, ifp->if_fib);
  807         netisr_dispatch(isr, m);
  808         return (0);
  809 }
  810 
  811 /*
  812  * Shutdown and remove the node and its associated interface.
  813  */
  814 static int
  815 ng_iface_shutdown(node_p node)
  816 {
  817         const priv_p priv = NG_NODE_PRIVATE(node);
  818 
  819         /*
  820          * The ifnet may be in a different vnet than the netgraph node, 
  821          * hence we have to change the current vnet context here.
  822          */
  823         CURVNET_SET_QUIET(priv->ifp->if_vnet);
  824         bpfdetach(priv->ifp);
  825         if_detach(priv->ifp);
  826         if_free(priv->ifp);
  827         CURVNET_RESTORE();
  828         priv->ifp = NULL;
  829         free_unr(V_ng_iface_unit, priv->unit);
  830         rm_destroy(&priv->lock);
  831         free(priv, M_NETGRAPH_IFACE);
  832         NG_NODE_SET_PRIVATE(node, NULL);
  833         NG_NODE_UNREF(node);
  834         return (0);
  835 }
  836 
  837 /*
  838  * Hook disconnection. Note that we do *not* shutdown when all
  839  * hooks have been disconnected.
  840  */
  841 static int
  842 ng_iface_disconnect(hook_p hook)
  843 {
  844         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  845         const iffam_p iffam = get_iffam_from_hook(priv, hook);
  846 
  847         if (iffam == NULL)
  848                 panic("%s", __func__);
  849         PRIV_WLOCK(priv);
  850         *get_hook_from_iffam(priv, iffam) = NULL;
  851         PRIV_WUNLOCK(priv);
  852         return (0);
  853 }
  854 
  855 /*
  856  * Handle loading and unloading for this node type.
  857  */
  858 static int
  859 ng_iface_mod_event(module_t mod, int event, void *data)
  860 {
  861         int error = 0;
  862 
  863         switch (event) {
  864         case MOD_LOAD:
  865         case MOD_UNLOAD:
  866                 break;
  867         default:
  868                 error = EOPNOTSUPP;
  869                 break;
  870         }
  871         return (error);
  872 }
  873 
  874 static void
  875 vnet_ng_iface_init(const void *unused)
  876 {
  877 
  878         V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
  879 }
  880 VNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
  881     vnet_ng_iface_init, NULL);
  882 
  883 static void
  884 vnet_ng_iface_uninit(const void *unused)
  885 {
  886 
  887         delete_unrhdr(V_ng_iface_unit);
  888 }
  889 VNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
  890     vnet_ng_iface_uninit, NULL);

Cache object: ab58176652dd515840efa00909944e21


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.