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 /*
    3  * ng_iface.c
    4  *
    5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    6  * All rights reserved.
    7  * 
    8  * Subject to the following obligations and disclaimer of warranty, use and
    9  * redistribution of this software, in source or object code forms, with or
   10  * without modifications are expressly permitted by Whistle Communications;
   11  * provided, however, that:
   12  * 1. Any and all reproductions of the source or object code must include the
   13  *    copyright notice above and the following disclaimer of warranties; and
   14  * 2. No rights are granted, in any manner or form, to use Whistle
   15  *    Communications, Inc. trademarks, including the mark "WHISTLE
   16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   17  *    such appears in the above copyright notice or in the software.
   18  * 
   19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   35  * OF SUCH DAMAGE.
   36  *
   37  * Author: Archie Cobbs <archie@freebsd.org>
   38  *
   39  * $FreeBSD$
   40  * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
   41  */
   42 
   43 /*
   44  * This node is also a system networking interface. It has
   45  * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
   46  * are simply relayed between the interface and the hooks.
   47  *
   48  * Interfaces are named ng0, ng1, etc.  New nodes take the
   49  * first available interface name.
   50  *
   51  * This node also includes Berkeley packet filter support.
   52  */
   53 
   54 #include <sys/param.h>
   55 #include <sys/systm.h>
   56 #include <sys/errno.h>
   57 #include <sys/kernel.h>
   58 #include <sys/malloc.h>
   59 #include <sys/mbuf.h>
   60 #include <sys/errno.h>
   61 #include <sys/sockio.h>
   62 #include <sys/socket.h>
   63 #include <sys/syslog.h>
   64 #include <sys/libkern.h>
   65 
   66 #include <net/if.h>
   67 #include <net/if_types.h>
   68 #include <net/intrq.h>
   69 #include <net/bpf.h>
   70 
   71 #include <netinet/in.h>
   72 
   73 #include <netgraph/ng_message.h>
   74 #include <netgraph/netgraph.h>
   75 #include <netgraph/ng_parse.h>
   76 #include <netgraph/ng_iface.h>
   77 #include <netgraph/ng_cisco.h>
   78 
   79 /* This struct describes one address family */
   80 struct iffam {
   81         sa_family_t     family;         /* Address family */
   82         const char      *hookname;      /* Name for hook */
   83 };
   84 typedef const struct iffam *iffam_p;
   85 
   86 /* List of address families supported by our interface */
   87 const static struct iffam gFamilies[] = {
   88         { AF_INET,      NG_IFACE_HOOK_INET      },
   89         { AF_INET6,     NG_IFACE_HOOK_INET6     },
   90         { AF_APPLETALK, NG_IFACE_HOOK_ATALK     },
   91         { AF_IPX,       NG_IFACE_HOOK_IPX       },
   92         { AF_ATM,       NG_IFACE_HOOK_ATM       },
   93         { AF_NATM,      NG_IFACE_HOOK_NATM      },
   94         { AF_NS,        NG_IFACE_HOOK_NS        },
   95 };
   96 #define NUM_FAMILIES            (sizeof(gFamilies) / sizeof(*gFamilies))
   97 
   98 /* Node private data */
   99 struct ng_iface_private {
  100         struct  ifnet *ifp;             /* Our interface */
  101         int     unit;                   /* Interface unit number */
  102         node_p  node;                   /* Our netgraph node */
  103         hook_p  hooks[NUM_FAMILIES];    /* Hook for each address family */
  104 };
  105 typedef struct ng_iface_private *priv_p;
  106 
  107 /* Interface methods */
  108 static void     ng_iface_start(struct ifnet *ifp);
  109 static int      ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
  110 static int      ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
  111                         struct sockaddr *dst, struct rtentry *rt0);
  112 static void     ng_iface_bpftap(struct ifnet *ifp,
  113                         struct mbuf *m, sa_family_t family);
  114 #ifdef DEBUG
  115 static void     ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
  116 #endif
  117 
  118 /* Netgraph methods */
  119 static ng_constructor_t ng_iface_constructor;
  120 static ng_rcvmsg_t      ng_iface_rcvmsg;
  121 static ng_shutdown_t    ng_iface_rmnode;
  122 static ng_newhook_t     ng_iface_newhook;
  123 static ng_rcvdata_t     ng_iface_rcvdata;
  124 static ng_disconnect_t  ng_iface_disconnect;
  125 
  126 /* Helper stuff */
  127 static iffam_p  get_iffam_from_af(sa_family_t family);
  128 static iffam_p  get_iffam_from_hook(priv_p priv, hook_p hook);
  129 static iffam_p  get_iffam_from_name(const char *name);
  130 static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
  131 
  132 /* Parse type for struct ng_iface_ifname */
  133 static const struct ng_parse_fixedstring_info ng_iface_ifname_info = {
  134         NG_IFACE_IFACE_NAME_MAX + 1
  135 };
  136 static const struct ng_parse_type ng_iface_ifname_type = {
  137         &ng_parse_fixedstring_type,
  138         &ng_iface_ifname_info
  139 };
  140 
  141 /* Parse type for struct ng_cisco_ipaddr */
  142 static const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
  143         = NG_CISCO_IPADDR_TYPE_INFO;
  144 static const struct ng_parse_type ng_cisco_ipaddr_type = {
  145         &ng_parse_struct_type,
  146         &ng_cisco_ipaddr_type_fields
  147 };
  148 
  149 /* List of commands and how to convert arguments to/from ASCII */
  150 static const struct ng_cmdlist ng_iface_cmds[] = {
  151         {
  152           NGM_IFACE_COOKIE,
  153           NGM_IFACE_GET_IFNAME,
  154           "getifname",
  155           NULL,
  156           &ng_iface_ifname_type
  157         },
  158         {
  159           NGM_IFACE_COOKIE,
  160           NGM_IFACE_POINT2POINT,
  161           "point2point",
  162           NULL,
  163           NULL
  164         },
  165         {
  166           NGM_IFACE_COOKIE,
  167           NGM_IFACE_BROADCAST,
  168           "broadcast",
  169           NULL,
  170           NULL
  171         },
  172         {
  173           NGM_CISCO_COOKIE,
  174           NGM_CISCO_GET_IPADDR,
  175           "getipaddr",
  176           NULL,
  177           &ng_cisco_ipaddr_type
  178         },
  179         { 0 }
  180 };
  181 
  182 /* Node type descriptor */
  183 static struct ng_type typestruct = {
  184         NG_VERSION,
  185         NG_IFACE_NODE_TYPE,
  186         NULL,
  187         ng_iface_constructor,
  188         ng_iface_rcvmsg,
  189         ng_iface_rmnode,
  190         ng_iface_newhook,
  191         NULL,
  192         NULL,
  193         ng_iface_rcvdata,
  194         ng_iface_rcvdata,
  195         ng_iface_disconnect,
  196         ng_iface_cmds
  197 };
  198 NETGRAPH_INIT(iface, &typestruct);
  199 
  200 /* We keep a bitmap indicating which unit numbers are free.
  201    One means the unit number is free, zero means it's taken. */
  202 static int      *ng_iface_units = NULL;
  203 static int      ng_iface_units_len = 0;
  204 
  205 #define UNITS_BITSPERWORD       (sizeof(*ng_iface_units) * NBBY)
  206 
  207 /************************************************************************
  208                         HELPER STUFF
  209  ************************************************************************/
  210 
  211 /*
  212  * Get the family descriptor from the family ID
  213  */
  214 static __inline__ iffam_p
  215 get_iffam_from_af(sa_family_t family)
  216 {
  217         iffam_p iffam;
  218         int k;
  219 
  220         for (k = 0; k < NUM_FAMILIES; k++) {
  221                 iffam = &gFamilies[k];
  222                 if (iffam->family == family)
  223                         return (iffam);
  224         }
  225         return (NULL);
  226 }
  227 
  228 /*
  229  * Get the family descriptor from the hook
  230  */
  231 static __inline__ iffam_p
  232 get_iffam_from_hook(priv_p priv, hook_p hook)
  233 {
  234         int k;
  235 
  236         for (k = 0; k < NUM_FAMILIES; k++)
  237                 if (priv->hooks[k] == hook)
  238                         return (&gFamilies[k]);
  239         return (NULL);
  240 }
  241 
  242 /*
  243  * Get the hook from the iffam descriptor
  244  */
  245 
  246 static __inline__ hook_p *
  247 get_hook_from_iffam(priv_p priv, iffam_p iffam)
  248 {
  249         return (&priv->hooks[iffam - gFamilies]);
  250 }
  251 
  252 /*
  253  * Get the iffam descriptor from the name
  254  */
  255 static __inline__ iffam_p
  256 get_iffam_from_name(const char *name)
  257 {
  258         iffam_p iffam;
  259         int k;
  260 
  261         for (k = 0; k < NUM_FAMILIES; k++) {
  262                 iffam = &gFamilies[k];
  263                 if (!strcmp(iffam->hookname, name))
  264                         return (iffam);
  265         }
  266         return (NULL);
  267 }
  268 
  269 /*
  270  * Find the first free unit number for a new interface.
  271  * Increase the size of the unit bitmap as necessary.
  272  */
  273 static __inline__ int
  274 ng_iface_get_unit(int *unit)
  275 {
  276         int index, bit;
  277 
  278         for (index = 0; index < ng_iface_units_len
  279             && ng_iface_units[index] == 0; index++);
  280         if (index == ng_iface_units_len) {              /* extend array */
  281                 int i, *newarray, newlen;
  282 
  283                 newlen = (2 * ng_iface_units_len) + 4;
  284                 MALLOC(newarray, int *, newlen * sizeof(*ng_iface_units),
  285                     M_NETGRAPH, M_NOWAIT);
  286                 if (newarray == NULL)
  287                         return (ENOMEM);
  288                 bcopy(ng_iface_units, newarray,
  289                     ng_iface_units_len * sizeof(*ng_iface_units));
  290                 for (i = ng_iface_units_len; i < newlen; i++)
  291                         newarray[i] = ~0;
  292                 if (ng_iface_units != NULL)
  293                         FREE(ng_iface_units, M_NETGRAPH);
  294                 ng_iface_units = newarray;
  295                 ng_iface_units_len = newlen;
  296         }
  297         bit = ffs(ng_iface_units[index]) - 1;
  298         KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1,
  299             ("%s: word=%d bit=%d", __FUNCTION__, ng_iface_units[index], bit));
  300         ng_iface_units[index] &= ~(1 << bit);
  301         *unit = (index * UNITS_BITSPERWORD) + bit;
  302         return (0);
  303 }
  304 
  305 /*
  306  * Free a no longer needed unit number.
  307  */
  308 static __inline__ void
  309 ng_iface_free_unit(int unit)
  310 {
  311         int index, bit;
  312 
  313         index = unit / UNITS_BITSPERWORD;
  314         bit = unit % UNITS_BITSPERWORD;
  315         KASSERT(index < ng_iface_units_len,
  316             ("%s: unit=%d len=%d", __FUNCTION__, unit, ng_iface_units_len));
  317         KASSERT((ng_iface_units[index] & (1 << bit)) == 0,
  318             ("%s: unit=%d is free", __FUNCTION__, unit));
  319         ng_iface_units[index] |= (1 << bit);
  320         /*
  321          * XXX We could think about reducing the size of ng_iface_units[]
  322          * XXX here if the last portion is all ones
  323          */
  324 }
  325 
  326 /************************************************************************
  327                         INTERFACE STUFF
  328  ************************************************************************/
  329 
  330 /*
  331  * Process an ioctl for the virtual interface
  332  */
  333 static int
  334 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  335 {
  336         struct ifreq *const ifr = (struct ifreq *) data;
  337         int s, error = 0;
  338 
  339 #ifdef DEBUG
  340         ng_iface_print_ioctl(ifp, command, data);
  341 #endif
  342         s = splimp();
  343         switch (command) {
  344 
  345         /* These two are mostly handled at a higher layer */
  346         case SIOCSIFADDR:
  347                 ifp->if_flags |= (IFF_UP | IFF_RUNNING);
  348                 ifp->if_flags &= ~(IFF_OACTIVE);
  349                 break;
  350         case SIOCGIFADDR:
  351                 break;
  352 
  353         /* Set flags */
  354         case SIOCSIFFLAGS:
  355                 /*
  356                  * If the interface is marked up and stopped, then start it.
  357                  * If it is marked down and running, then stop it.
  358                  */
  359                 if (ifr->ifr_flags & IFF_UP) {
  360                         if (!(ifp->if_flags & IFF_RUNNING)) {
  361                                 ifp->if_flags &= ~(IFF_OACTIVE);
  362                                 ifp->if_flags |= IFF_RUNNING;
  363                         }
  364                 } else {
  365                         if (ifp->if_flags & IFF_RUNNING)
  366                                 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
  367                 }
  368                 break;
  369 
  370         /* Set the interface MTU */
  371         case SIOCSIFMTU:
  372                 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
  373                     || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
  374                         error = EINVAL;
  375                 else
  376                         ifp->if_mtu = ifr->ifr_mtu;
  377                 break;
  378 
  379         /* Stuff that's not supported */
  380         case SIOCADDMULTI:
  381         case SIOCDELMULTI:
  382                 error = 0;
  383                 break;
  384         case SIOCSIFPHYS:
  385                 error = EOPNOTSUPP;
  386                 break;
  387 
  388         default:
  389                 error = EINVAL;
  390                 break;
  391         }
  392         (void) splx(s);
  393         return (error);
  394 }
  395 
  396 /*
  397  * This routine is called to deliver a packet out the interface.
  398  * We simply look at the address family and relay the packet to
  399  * the corresponding hook, if it exists and is connected.
  400  */
  401 
  402 static int
  403 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
  404                 struct sockaddr *dst, struct rtentry *rt0)
  405 {
  406         const priv_p priv = (priv_p) ifp->if_softc;
  407         const iffam_p iffam = get_iffam_from_af(dst->sa_family);
  408         meta_p meta = NULL;
  409         int len, error = 0;
  410 
  411         /* Check interface flags */
  412         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  413                 m_freem(m);
  414                 return (ENETDOWN);
  415         }
  416 
  417         /* BPF writes need to be handled specially */
  418         if (dst->sa_family == AF_UNSPEC) {
  419                 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
  420                         return (ENOBUFS);
  421                 dst->sa_family = (sa_family_t)*mtod(m, int32_t *);
  422                 m->m_data += 4;
  423                 m->m_len -= 4;
  424                 m->m_pkthdr.len -= 4;
  425         }
  426 
  427         /* Berkeley packet filter */
  428         ng_iface_bpftap(ifp, m, dst->sa_family);
  429 
  430         /* Check address family to determine hook (if known) */
  431         if (iffam == NULL) {
  432                 m_freem(m);
  433                 log(LOG_WARNING, "%s%d: can't handle af%d\n",
  434                        ifp->if_name, ifp->if_unit, (int)dst->sa_family);
  435                 return (EAFNOSUPPORT);
  436         }
  437 
  438         /* Copy length before the mbuf gets invalidated */
  439         len = m->m_pkthdr.len;
  440 
  441         /* Send packet; if hook is not connected, mbuf will get freed. */
  442         NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);
  443 
  444         /* Update stats */
  445         if (error == 0) {
  446                 ifp->if_obytes += len;
  447                 ifp->if_opackets++;
  448         }
  449         return (error);
  450 }
  451 
  452 /*
  453  * This routine should never be called
  454  */
  455 
  456 static void
  457 ng_iface_start(struct ifnet *ifp)
  458 {
  459         printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__);
  460 }
  461 
  462 /*
  463  * Flash a packet by the BPF (requires prepending 4 byte AF header)
  464  * Note the phoney mbuf; this is OK because BPF treats it read-only.
  465  */
  466 static void
  467 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
  468 {
  469         int32_t family4 = (int32_t)family;
  470         struct mbuf m0;
  471 
  472         KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __FUNCTION__));
  473         if (ifp->if_bpf != NULL) {
  474                 bzero(&m0, sizeof(m0));
  475                 m0.m_next = m;
  476                 m0.m_len = sizeof(family4);
  477                 m0.m_data = (char *)&family4;
  478                 bpf_mtap(ifp, &m0);
  479         }
  480 }
  481 
  482 #ifdef DEBUG
  483 /*
  484  * Display an ioctl to the virtual interface
  485  */
  486 
  487 static void
  488 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
  489 {
  490         char   *str;
  491 
  492         switch (command & IOC_DIRMASK) {
  493         case IOC_VOID:
  494                 str = "IO";
  495                 break;
  496         case IOC_OUT:
  497                 str = "IOR";
  498                 break;
  499         case IOC_IN:
  500                 str = "IOW";
  501                 break;
  502         case IOC_INOUT:
  503                 str = "IORW";
  504                 break;
  505         default:
  506                 str = "IO??";
  507         }
  508         log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n",
  509                ifp->if_name, ifp->if_unit,
  510                str,
  511                IOCGROUP(command),
  512                command & 0xff,
  513                IOCPARM_LEN(command));
  514 }
  515 #endif /* DEBUG */
  516 
  517 /************************************************************************
  518                         NETGRAPH NODE STUFF
  519  ************************************************************************/
  520 
  521 /*
  522  * Constructor for a node
  523  */
  524 static int
  525 ng_iface_constructor(node_p *nodep)
  526 {
  527         char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
  528         struct ifnet *ifp;
  529         node_p node;
  530         priv_p priv;
  531         int error = 0;
  532 
  533         /* Allocate node and interface private structures */
  534         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT);
  535         if (priv == NULL)
  536                 return (ENOMEM);
  537         bzero(priv, sizeof(*priv));
  538         MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_NOWAIT);
  539         if (ifp == NULL) {
  540                 FREE(priv, M_NETGRAPH);
  541                 return (ENOMEM);
  542         }
  543         bzero(ifp, sizeof(*ifp));
  544 
  545         /* Link them together */
  546         ifp->if_softc = priv;
  547         priv->ifp = ifp;
  548 
  549         /* Get an interface unit number */
  550         if ((error = ng_iface_get_unit(&priv->unit)) != 0) {
  551                 FREE(ifp, M_NETGRAPH);
  552                 FREE(priv, M_NETGRAPH);
  553                 return (error);
  554         }
  555 
  556         /* Call generic node constructor */
  557         if ((error = ng_make_node_common(&typestruct, nodep)) != 0) {
  558                 ng_iface_free_unit(priv->unit);
  559                 FREE(ifp, M_NETGRAPH);
  560                 FREE(priv, M_NETGRAPH);
  561                 return (error);
  562         }
  563         node = *nodep;
  564 
  565         /* Link together node and private info */
  566         node->private = priv;
  567         priv->node = node;
  568 
  569         /* Initialize interface structure */
  570         ifp->if_name = NG_IFACE_IFACE_NAME;
  571         ifp->if_unit = priv->unit;
  572         ifp->if_output = ng_iface_output;
  573         ifp->if_start = ng_iface_start;
  574         ifp->if_ioctl = ng_iface_ioctl;
  575         ifp->if_watchdog = NULL;
  576         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  577         ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
  578         ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
  579         ifp->if_type = IFT_PROPVIRTUAL;         /* XXX */
  580         ifp->if_addrlen = 0;                    /* XXX */
  581         ifp->if_hdrlen = 0;                     /* XXX */
  582         ifp->if_baudrate = 64000;               /* XXX */
  583         TAILQ_INIT(&ifp->if_addrhead);
  584 
  585         /* Give this node the same name as the interface (if possible) */
  586         bzero(ifname, sizeof(ifname));
  587         snprintf(ifname, sizeof(ifname), "%s%d", ifp->if_name, ifp->if_unit);
  588         if (ng_name_node(node, ifname) != 0)
  589                 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname);
  590 
  591         /* Attach the interface */
  592         if_attach(ifp);
  593         bpfattach(ifp, DLT_NULL, sizeof(u_int));
  594 
  595         /* Done */
  596         return (0);
  597 }
  598 
  599 /*
  600  * Give our ok for a hook to be added
  601  */
  602 static int
  603 ng_iface_newhook(node_p node, hook_p hook, const char *name)
  604 {
  605         const iffam_p iffam = get_iffam_from_name(name);
  606         hook_p *hookptr;
  607 
  608         if (iffam == NULL)
  609                 return (EPFNOSUPPORT);
  610         hookptr = get_hook_from_iffam((priv_p) node->private, iffam);
  611         if (*hookptr != NULL)
  612                 return (EISCONN);
  613         *hookptr = hook;
  614         return (0);
  615 }
  616 
  617 /*
  618  * Receive a control message
  619  */
  620 static int
  621 ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
  622                 const char *retaddr, struct ng_mesg **rptr)
  623 {
  624         const priv_p priv = node->private;
  625         struct ifnet *const ifp = priv->ifp;
  626         struct ng_mesg *resp = NULL;
  627         int error = 0;
  628 
  629         switch (msg->header.typecookie) {
  630         case NGM_IFACE_COOKIE:
  631                 switch (msg->header.cmd) {
  632                 case NGM_IFACE_GET_IFNAME:
  633                     {
  634                         struct ng_iface_ifname *arg;
  635 
  636                         NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
  637                         if (resp == NULL) {
  638                                 error = ENOMEM;
  639                                 break;
  640                         }
  641                         arg = (struct ng_iface_ifname *)resp->data;
  642                         snprintf(arg->ngif_name, sizeof(arg->ngif_name),
  643                             "%s%d", ifp->if_name, ifp->if_unit);
  644                         break;
  645                     }
  646 
  647                 case NGM_IFACE_POINT2POINT:
  648                 case NGM_IFACE_BROADCAST:
  649                     {
  650 
  651                         /* Deny request if interface is UP */
  652                         if ((ifp->if_flags & IFF_UP) != 0)
  653                                 return (EBUSY);
  654 
  655                         /* Change flags */
  656                         switch (msg->header.cmd) {
  657                         case NGM_IFACE_POINT2POINT:
  658                                 ifp->if_flags |= IFF_POINTOPOINT;
  659                                 ifp->if_flags &= ~IFF_BROADCAST;
  660                                 break;
  661                         case NGM_IFACE_BROADCAST:
  662                                 ifp->if_flags &= ~IFF_POINTOPOINT;
  663                                 ifp->if_flags |= IFF_BROADCAST;
  664                                 break;
  665                         }
  666                         break;
  667                     }
  668 
  669                 default:
  670                         error = EINVAL;
  671                         break;
  672                 }
  673                 break;
  674         case NGM_CISCO_COOKIE:
  675                 switch (msg->header.cmd) {
  676                 case NGM_CISCO_GET_IPADDR:      /* we understand this too */
  677                     {
  678                         struct ifaddr *ifa;
  679 
  680                         /* Return the first configured IP address */
  681                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  682                                 struct ng_cisco_ipaddr *ips;
  683 
  684                                 if (ifa->ifa_addr->sa_family != AF_INET)
  685                                         continue;
  686                                 NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
  687                                 if (resp == NULL) {
  688                                         error = ENOMEM;
  689                                         break;
  690                                 }
  691                                 ips = (struct ng_cisco_ipaddr *)resp->data;
  692                                 ips->ipaddr = ((struct sockaddr_in *)
  693                                                 ifa->ifa_addr)->sin_addr;
  694                                 ips->netmask = ((struct sockaddr_in *)
  695                                                 ifa->ifa_netmask)->sin_addr;
  696                                 break;
  697                         }
  698 
  699                         /* No IP addresses on this interface? */
  700                         if (ifa == NULL)
  701                                 error = EADDRNOTAVAIL;
  702                         break;
  703                     }
  704                 default:
  705                         error = EINVAL;
  706                         break;
  707                 }
  708                 break;
  709         default:
  710                 error = EINVAL;
  711                 break;
  712         }
  713         if (rptr)
  714                 *rptr = resp;
  715         else if (resp)
  716                 FREE(resp, M_NETGRAPH);
  717         FREE(msg, M_NETGRAPH);
  718         return (error);
  719 }
  720 
  721 /*
  722  * Recive data from a hook. Pass the packet to the correct input routine.
  723  */
  724 static int
  725 ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
  726 {
  727         const priv_p priv = hook->node->private;
  728         const iffam_p iffam = get_iffam_from_hook(priv, hook);
  729         struct ifnet *const ifp = priv->ifp;
  730 
  731         /* Sanity checks */
  732         KASSERT(iffam != NULL, ("%s: iffam", __FUNCTION__));
  733         KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__));
  734         if (m == NULL)
  735                 return (EINVAL);
  736         if ((ifp->if_flags & IFF_UP) == 0) {
  737                 NG_FREE_DATA(m, meta);
  738                 return (ENETDOWN);
  739         }
  740 
  741         /* Update interface stats */
  742         ifp->if_ipackets++;
  743         ifp->if_ibytes += m->m_pkthdr.len;
  744 
  745         /* Note receiving interface */
  746         m->m_pkthdr.rcvif = ifp;
  747 
  748         /* Berkeley packet filter */
  749         ng_iface_bpftap(ifp, m, iffam->family);
  750 
  751         /* Ignore any meta-data */
  752         NG_FREE_META(meta);
  753 
  754         /* Send packet */
  755         return family_enqueue(iffam->family, m);
  756 }
  757 
  758 /*
  759  * Shutdown and remove the node and its associated interface.
  760  */
  761 static int
  762 ng_iface_rmnode(node_p node)
  763 {
  764         const priv_p priv = node->private;
  765 
  766         ng_cutlinks(node);
  767         ng_unname(node);
  768         bpfdetach(priv->ifp);
  769         if_detach(priv->ifp);
  770         FREE(priv->ifp, M_NETGRAPH);
  771         priv->ifp = NULL;
  772         ng_iface_free_unit(priv->unit);
  773         FREE(priv, M_NETGRAPH);
  774         node->private = NULL;
  775         ng_unref(node);
  776         return (0);
  777 }
  778 
  779 /*
  780  * Hook disconnection. Note that we do *not* shutdown when all
  781  * hooks have been disconnected.
  782  */
  783 static int
  784 ng_iface_disconnect(hook_p hook)
  785 {
  786         const priv_p priv = hook->node->private;
  787         const iffam_p iffam = get_iffam_from_hook(priv, hook);
  788 
  789         if (iffam == NULL)
  790                 panic(__FUNCTION__);
  791         *get_hook_from_iffam(priv, iffam) = NULL;
  792         return (0);
  793 }
  794 

Cache object: 023e4eb846d4f8b8fb8c51c67be4a1d6


[ 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.