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_ether.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_ether.c
    4  *
    5  * Copyright (c) 1996-2000 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  * Authors: Archie Cobbs <archie@freebsd.org>
   38  *          Julian Elischer <julian@freebsd.org>
   39  *
   40  * $FreeBSD$
   41  */
   42 
   43 /*
   44  * ng_ether(4) netgraph node type
   45  */
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/kernel.h>
   50 #include <sys/malloc.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/errno.h>
   53 #include <sys/syslog.h>
   54 #include <sys/socket.h>
   55 
   56 #include <net/if.h>
   57 #include <net/if_types.h>
   58 #include <net/if_arp.h>
   59 #include <net/if_var.h>
   60 #include <net/ethernet.h>
   61 
   62 #include <netgraph/ng_message.h>
   63 #include <netgraph/netgraph.h>
   64 #include <netgraph/ng_parse.h>
   65 #include <netgraph/ng_ether.h>
   66 
   67 #define IFP2AC(IFP)  ((struct arpcom *)IFP)
   68 #define IFP2NG(ifp)  ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
   69 
   70 /* Per-node private data */
   71 struct private {
   72         struct ifnet    *ifp;           /* associated interface */
   73         hook_p          upper;          /* upper hook connection */
   74         hook_p          lower;          /* lower hook connection */
   75         hook_p          orphan;         /* orphan hook connection */
   76         u_char          autoSrcAddr;    /* always overwrite source address */
   77         u_char          promisc;        /* promiscuous mode enabled */
   78         u_long          hwassist;       /* hardware checksum capabilities */
   79 };
   80 typedef struct private *priv_p;
   81 
   82 /* Functional hooks called from if_ethersubr.c */
   83 static void     ng_ether_input(struct ifnet *ifp,
   84                     struct mbuf **mp, struct ether_header *eh);
   85 static void     ng_ether_input_orphan(struct ifnet *ifp,
   86                     struct mbuf *m, struct ether_header *eh);
   87 static int      ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
   88 static void     ng_ether_attach(struct ifnet *ifp);
   89 static void     ng_ether_detach(struct ifnet *ifp); 
   90 
   91 /* Other functions */
   92 static void     ng_ether_input2(hook_p hook,
   93                     struct mbuf **mp, struct ether_header *eh);
   94 static int      ng_ether_glueback_header(struct mbuf **mp,
   95                         struct ether_header *eh);
   96 static int      ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta);
   97 static int      ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta);
   98 
   99 /* Netgraph node methods */
  100 static ng_constructor_t ng_ether_constructor;
  101 static ng_rcvmsg_t      ng_ether_rcvmsg;
  102 static ng_shutdown_t    ng_ether_rmnode;
  103 static ng_newhook_t     ng_ether_newhook;
  104 static ng_rcvdata_t     ng_ether_rcvdata;
  105 static ng_disconnect_t  ng_ether_disconnect;
  106 static int              ng_ether_mod_event(module_t mod, int event, void *data);
  107 
  108 /* List of commands and how to convert arguments to/from ASCII */
  109 static const struct ng_cmdlist ng_ether_cmdlist[] = {
  110         {
  111           NGM_ETHER_COOKIE,
  112           NGM_ETHER_GET_IFNAME,
  113           "getifname",
  114           NULL,
  115           &ng_parse_string_type
  116         },
  117         {
  118           NGM_ETHER_COOKIE,
  119           NGM_ETHER_GET_IFINDEX,
  120           "getifindex",
  121           NULL,
  122           &ng_parse_int32_type
  123         },
  124         {
  125           NGM_ETHER_COOKIE,
  126           NGM_ETHER_GET_ENADDR,
  127           "getenaddr",
  128           NULL,
  129           &ng_parse_enaddr_type
  130         },
  131         {
  132           NGM_ETHER_COOKIE,
  133           NGM_ETHER_SET_ENADDR,
  134           "setenaddr",
  135           &ng_parse_enaddr_type,
  136           NULL
  137         },
  138         {
  139           NGM_ETHER_COOKIE,
  140           NGM_ETHER_GET_PROMISC,
  141           "getpromisc",
  142           NULL,
  143           &ng_parse_int32_type
  144         },
  145         {
  146           NGM_ETHER_COOKIE,
  147           NGM_ETHER_SET_PROMISC,
  148           "setpromisc",
  149           &ng_parse_int32_type,
  150           NULL
  151         },
  152         {
  153           NGM_ETHER_COOKIE,
  154           NGM_ETHER_GET_AUTOSRC,
  155           "getautosrc",
  156           NULL,
  157           &ng_parse_int32_type
  158         },
  159         {
  160           NGM_ETHER_COOKIE,
  161           NGM_ETHER_SET_AUTOSRC,
  162           "setautosrc",
  163           &ng_parse_int32_type,
  164           NULL
  165         },
  166         { 0 }
  167 };
  168 
  169 static struct ng_type ng_ether_typestruct = {
  170         NG_VERSION,
  171         NG_ETHER_NODE_TYPE,
  172         ng_ether_mod_event,
  173         ng_ether_constructor,
  174         ng_ether_rcvmsg,
  175         ng_ether_rmnode,
  176         ng_ether_newhook,
  177         NULL,
  178         NULL,
  179         ng_ether_rcvdata,
  180         ng_ether_rcvdata,
  181         ng_ether_disconnect,
  182         ng_ether_cmdlist,
  183 };
  184 NETGRAPH_INIT(ether, &ng_ether_typestruct);
  185 
  186 /******************************************************************
  187                     ETHERNET FUNCTION HOOKS
  188 ******************************************************************/
  189 
  190 /*
  191  * Handle a packet that has come in on an interface. We get to
  192  * look at it here before any upper layer protocols do.
  193  *
  194  * NOTE: this function will get called at splimp()
  195  */
  196 static void
  197 ng_ether_input(struct ifnet *ifp,
  198         struct mbuf **mp, struct ether_header *eh)
  199 {
  200         const node_p node = IFP2NG(ifp);
  201         const priv_p priv = node->private;
  202 
  203         /* If "lower" hook not connected, let packet continue */
  204         if (priv->lower == NULL)
  205                 return;
  206         ng_ether_input2(priv->lower, mp, eh);
  207 }
  208 
  209 /*
  210  * Handle a packet that has come in on an interface, and which
  211  * does not match any of our known protocols (an ``orphan'').
  212  *
  213  * NOTE: this function will get called at splimp()
  214  */
  215 static void
  216 ng_ether_input_orphan(struct ifnet *ifp,
  217         struct mbuf *m, struct ether_header *eh)
  218 {
  219         const node_p node = IFP2NG(ifp);
  220         const priv_p priv = node->private;
  221 
  222         /* If "orphan" hook not connected, let packet continue */
  223         if (priv->orphan == NULL) {
  224                 m_freem(m);
  225                 return;
  226         }
  227         ng_ether_input2(priv->orphan, &m, eh);
  228         if (m != NULL)
  229                 m_freem(m);
  230 }
  231 
  232 /*
  233  * Handle a packet that has come in on an interface.
  234  * The Ethernet header has already been detached from the mbuf,
  235  * so we have to put it back.
  236  *
  237  * NOTE: this function will get called at splimp()
  238  */
  239 static void
  240 ng_ether_input2(hook_p hook, struct mbuf **mp, struct ether_header *eh)
  241 {
  242         const priv_p priv = hook->node->private;
  243         meta_p meta = NULL;
  244         int error;
  245 
  246         /* Glue Ethernet header back on */
  247         if ((error = ng_ether_glueback_header(mp, eh)) != 0)
  248                 return;
  249 
  250         /* Send out lower/orphan hook */
  251         (void)ng_queue_data(hook, *mp, meta);
  252         *mp = NULL;
  253 }
  254 
  255 /*
  256  * Handle a packet that is going out on an interface.
  257  * The Ethernet header is already attached to the mbuf.
  258  */
  259 static int
  260 ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
  261 {
  262         const node_p node = IFP2NG(ifp);
  263         const priv_p priv = node->private;
  264         meta_p meta = NULL;
  265         int error = 0;
  266 
  267         /* If "upper" hook not connected, let packet continue */
  268         if (priv->upper == NULL)
  269                 return (0);
  270 
  271         /* Send it out "upper" hook */
  272         NG_SEND_DATA(error, priv->upper, *mp, meta);
  273         *mp = NULL;
  274         return (error);
  275 }
  276 
  277 /*
  278  * A new Ethernet interface has been attached.
  279  * Create a new node for it, etc.
  280  */
  281 static void
  282 ng_ether_attach(struct ifnet *ifp)
  283 {
  284         char name[IFNAMSIZ + 1];
  285         priv_p priv;
  286         node_p node;
  287 
  288         /* Create node */
  289         KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__));
  290         snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit);
  291         if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
  292                 log(LOG_ERR, "%s: can't %s for %s\n",
  293                     __FUNCTION__, "create node", name);
  294                 return;
  295         }
  296 
  297         /* Allocate private data */
  298         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT);
  299         if (priv == NULL) {
  300                 log(LOG_ERR, "%s: can't %s for %s\n",
  301                     __FUNCTION__, "allocate memory", name);
  302                 ng_unref(node);
  303                 return;
  304         }
  305         bzero(priv, sizeof(*priv));
  306         node->private = priv;
  307         priv->ifp = ifp;
  308         IFP2NG(ifp) = node;
  309         priv->autoSrcAddr = 1;
  310         priv->hwassist = ifp->if_hwassist;
  311 
  312         /* Try to give the node the same name as the interface */
  313         if (ng_name_node(node, name) != 0) {
  314                 log(LOG_WARNING, "%s: can't name node %s\n",
  315                     __FUNCTION__, name);
  316         }
  317 }
  318 
  319 /*
  320  * An Ethernet interface is being detached.
  321  * Destroy its node.
  322  */
  323 static void
  324 ng_ether_detach(struct ifnet *ifp)
  325 {
  326         const node_p node = IFP2NG(ifp);
  327         priv_p priv;
  328 
  329         if (node == NULL)               /* no node (why not?), ignore */
  330                 return;
  331         ng_rmnode(node);                /* break all links to other nodes */
  332         node->flags |= NG_INVALID;
  333         ng_unname(node);                /* free name (and its reference) */
  334         IFP2NG(ifp) = NULL;             /* detach node from interface */
  335         priv = node->private;           /* free node private info */
  336         bzero(priv, sizeof(*priv));
  337         FREE(priv, M_NETGRAPH);
  338         node->private = NULL;
  339         ng_unref(node);                 /* free node itself */
  340 }
  341 
  342 /*
  343  * Optimization for gluing the Ethernet header back onto
  344  * the front of an incoming packet.
  345  */
  346 static int
  347 ng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh)
  348 {
  349         struct mbuf *m = *mp;
  350         int error = 0;
  351 
  352         /*
  353          * Optimize for the case where the header is already in place
  354          * at the front of the mbuf. This is actually quite likely
  355          * because many Ethernet drivers generate packets this way.
  356          */
  357         if (eh == mtod(m, struct ether_header *) - 1) {
  358                 m->m_len += sizeof(*eh);
  359                 m->m_data -= sizeof(*eh);
  360                 m->m_pkthdr.len += sizeof(*eh);
  361                 goto done;
  362         }
  363 
  364         /* Prepend the header back onto the front of the mbuf */
  365         M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
  366         if (m == NULL) {
  367                 error = ENOBUFS;
  368                 goto done;
  369         }
  370 
  371         /* Copy header into front of mbuf */
  372         bcopy(eh, mtod(m, void *), sizeof(*eh));
  373 
  374 done:
  375         /* Done */
  376         *mp = m;
  377         return error;
  378 }
  379 
  380 /******************************************************************
  381                     NETGRAPH NODE METHODS
  382 ******************************************************************/
  383 
  384 /*
  385  * It is not possible or allowable to create a node of this type.
  386  * Nodes get created when the interface is attached (or, when
  387  * this node type's KLD is loaded).
  388  */
  389 static int
  390 ng_ether_constructor(node_p *nodep)
  391 {
  392         return (EINVAL);
  393 }
  394 
  395 /*
  396  * Check for attaching a new hook.
  397  */
  398 static  int
  399 ng_ether_newhook(node_p node, hook_p hook, const char *name)
  400 {
  401         const priv_p priv = node->private;
  402         hook_p *hookptr;
  403 
  404         /* Divert hook is an alias for lower */
  405         if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
  406                 name = NG_ETHER_HOOK_LOWER;
  407 
  408         /* Which hook? */
  409         if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
  410                 hookptr = &priv->upper;
  411         else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0)
  412                 hookptr = &priv->lower;
  413         else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0)
  414                 hookptr = &priv->orphan;
  415         else
  416                 return (EINVAL);
  417 
  418         /* Check if already connected (shouldn't be, but doesn't hurt) */
  419         if (*hookptr != NULL)
  420                 return (EISCONN);
  421 
  422         /* Disable hardware checksums while 'upper' hook is connected */
  423         if (hookptr == &priv->upper)
  424                 priv->ifp->if_hwassist = 0;
  425 
  426         /* OK */
  427         *hookptr = hook;
  428         return (0);
  429 }
  430 
  431 /*
  432  * Receive an incoming control message.
  433  */
  434 static int
  435 ng_ether_rcvmsg(node_p node, struct ng_mesg *msg,
  436         const char *retaddr, struct ng_mesg **rptr)
  437 {
  438         const priv_p priv = node->private;
  439         struct ng_mesg *resp = NULL;
  440         int error = 0;
  441 
  442         switch (msg->header.typecookie) {
  443         case NGM_ETHER_COOKIE:
  444                 switch (msg->header.cmd) {
  445                 case NGM_ETHER_GET_IFNAME:
  446                         NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
  447                         if (resp == NULL) {
  448                                 error = ENOMEM;
  449                                 break;
  450                         }
  451                         snprintf(resp->data, IFNAMSIZ + 1,
  452                             "%s%d", priv->ifp->if_name, priv->ifp->if_unit);
  453                         break;
  454                 case NGM_ETHER_GET_IFINDEX:
  455                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  456                         if (resp == NULL) {
  457                                 error = ENOMEM;
  458                                 break;
  459                         }
  460                         *((u_int32_t *)resp->data) = priv->ifp->if_index;
  461                         break;
  462                 case NGM_ETHER_GET_ENADDR:
  463                         NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT);
  464                         if (resp == NULL) {
  465                                 error = ENOMEM;
  466                                 break;
  467                         }
  468                         bcopy((IFP2AC(priv->ifp))->ac_enaddr,
  469                             resp->data, ETHER_ADDR_LEN);
  470                         break;
  471                 case NGM_ETHER_SET_ENADDR:
  472                     {
  473                         if (msg->header.arglen != ETHER_ADDR_LEN) {
  474                                 error = EINVAL;
  475                                 break;
  476                         }
  477                         error = if_setlladdr(priv->ifp,
  478                             (u_char *)msg->data, ETHER_ADDR_LEN);
  479                         break;
  480                     }
  481                 case NGM_ETHER_GET_PROMISC:
  482                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  483                         if (resp == NULL) {
  484                                 error = ENOMEM;
  485                                 break;
  486                         }
  487                         *((u_int32_t *)resp->data) = priv->promisc;
  488                         break;
  489                 case NGM_ETHER_SET_PROMISC:
  490                     {
  491                         u_char want;
  492 
  493                         if (msg->header.arglen != sizeof(u_int32_t)) {
  494                                 error = EINVAL;
  495                                 break;
  496                         }
  497                         want = !!*((u_int32_t *)msg->data);
  498                         if (want ^ priv->promisc) {
  499                                 if ((error = ifpromisc(priv->ifp, want)) != 0)
  500                                         break;
  501                                 priv->promisc = want;
  502                         }
  503                         break;
  504                     }
  505                 case NGM_ETHER_GET_AUTOSRC:
  506                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  507                         if (resp == NULL) {
  508                                 error = ENOMEM;
  509                                 break;
  510                         }
  511                         *((u_int32_t *)resp->data) = priv->autoSrcAddr;
  512                         break;
  513                 case NGM_ETHER_SET_AUTOSRC:
  514                         if (msg->header.arglen != sizeof(u_int32_t)) {
  515                                 error = EINVAL;
  516                                 break;
  517                         }
  518                         priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
  519                         break;
  520                 default:
  521                         error = EINVAL;
  522                         break;
  523                 }
  524                 break;
  525         default:
  526                 error = EINVAL;
  527                 break;
  528         }
  529         if (rptr)
  530                 *rptr = resp;
  531         else if (resp != NULL)
  532                 FREE(resp, M_NETGRAPH);
  533         FREE(msg, M_NETGRAPH);
  534         return (error);
  535 }
  536 
  537 /*
  538  * Receive data on a hook.
  539  */
  540 static int
  541 ng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
  542 {
  543         const node_p node = hook->node;
  544         const priv_p priv = node->private;
  545 
  546         if (hook == priv->lower || hook == priv->orphan)
  547                 return ng_ether_rcv_lower(node, m, meta);
  548         if (hook == priv->upper)
  549                 return ng_ether_rcv_upper(node, m, meta);
  550         panic("%s: weird hook", __FUNCTION__);
  551 }
  552 
  553 /*
  554  * Handle an mbuf received on the "lower" or "orphan" hook.
  555  */
  556 static int
  557 ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta)
  558 {
  559         const priv_p priv = node->private;
  560         struct ifnet *const ifp = priv->ifp;
  561 
  562         /* Discard meta info */
  563         NG_FREE_META(meta);
  564 
  565         /* Check whether interface is ready for packets */
  566         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  567                 m_freem(m);
  568                 return (ENETDOWN);
  569         }
  570 
  571         /* Make sure header is fully pulled up */
  572         if (m->m_pkthdr.len < sizeof(struct ether_header)) {
  573                 m_freem(m);
  574                 return (EINVAL);
  575         }
  576         if (m->m_len < sizeof(struct ether_header)
  577             && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
  578                 return (ENOBUFS);
  579 
  580         /* Drop in the MAC address if desired */
  581         if (priv->autoSrcAddr) {
  582 
  583                 /* Make the mbuf writable if it's not already */
  584                 if (!M_WRITABLE(m)
  585                     && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
  586                         return (ENOBUFS);
  587 
  588                 /* Overwrite source MAC address */
  589                 bcopy((IFP2AC(ifp))->ac_enaddr,
  590                     mtod(m, struct ether_header *)->ether_shost,
  591                     ETHER_ADDR_LEN);
  592         }
  593 
  594         /* Send it on its way */
  595         return ether_output_frame(ifp, m);
  596 }
  597 
  598 /*
  599  * Handle an mbuf received on the "upper" hook.
  600  */
  601 static int
  602 ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta)
  603 {
  604         const priv_p priv = node->private;
  605         struct ether_header *eh;
  606 
  607         /* Discard meta info */
  608         NG_FREE_META(meta);
  609 
  610         /* Check length and pull off header */
  611         if (m->m_pkthdr.len < sizeof(*eh)) {
  612                 m_freem(m);
  613                 return (EINVAL);
  614         }
  615         if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL)
  616                 return (ENOBUFS);
  617         eh = mtod(m, struct ether_header *);
  618         m->m_data += sizeof(*eh);
  619         m->m_len -= sizeof(*eh);
  620         m->m_pkthdr.len -= sizeof(*eh);
  621         m->m_pkthdr.rcvif = priv->ifp;
  622 
  623         /* Route packet back in */
  624         ether_demux(priv->ifp, eh, m);
  625         return (0);
  626 }
  627 
  628 /*
  629  * Shutdown node. This resets the node but does not remove it.
  630  */
  631 static int
  632 ng_ether_rmnode(node_p node)
  633 {
  634         const priv_p priv = node->private;
  635 
  636         ng_cutlinks(node);
  637         node->flags &= ~NG_INVALID;     /* bounce back to life */
  638         if (priv->promisc) {            /* disable promiscuous mode */
  639                 (void)ifpromisc(priv->ifp, 0);
  640                 priv->promisc = 0;
  641         }
  642         priv->autoSrcAddr = 1;          /* reset auto-src-addr flag */
  643         return (0);
  644 }
  645 
  646 /*
  647  * Hook disconnection.
  648  */
  649 static int
  650 ng_ether_disconnect(hook_p hook)
  651 {
  652         const priv_p priv = hook->node->private;
  653 
  654         if (hook == priv->upper) {
  655                 priv->upper = NULL;
  656                 priv->ifp->if_hwassist = priv->hwassist;  /* restore h/w csum */
  657         } else if (hook == priv->lower)
  658                 priv->lower = NULL;
  659         else if (hook == priv->orphan)
  660                 priv->orphan = NULL;
  661         else
  662                 panic("%s: weird hook", __FUNCTION__);
  663         if (hook->node->numhooks == 0)
  664                 ng_rmnode(hook->node);  /* reset node */
  665         return (0);
  666 }
  667 
  668 /******************************************************************
  669                         INITIALIZATION
  670 ******************************************************************/
  671 
  672 /*
  673  * Handle loading and unloading for this node type.
  674  */
  675 static int
  676 ng_ether_mod_event(module_t mod, int event, void *data)
  677 {
  678         struct ifnet *ifp;
  679         int error = 0;
  680         int s;
  681 
  682         s = splnet();
  683         switch (event) {
  684         case MOD_LOAD:
  685 
  686                 /* Register function hooks */
  687                 if (ng_ether_attach_p != NULL) {
  688                         error = EEXIST;
  689                         break;
  690                 }
  691                 ng_ether_attach_p = ng_ether_attach;
  692                 ng_ether_detach_p = ng_ether_detach;
  693                 ng_ether_output_p = ng_ether_output;
  694                 ng_ether_input_p = ng_ether_input;
  695                 ng_ether_input_orphan_p = ng_ether_input_orphan;
  696 
  697                 /* Create nodes for any already-existing Ethernet interfaces */
  698                 TAILQ_FOREACH(ifp, &ifnet, if_link) {
  699                         if (ifp->if_type == IFT_ETHER ||
  700                             ifp->if_type == IFT_L2VLAN)
  701                                 ng_ether_attach(ifp);
  702                 }
  703                 break;
  704 
  705         case MOD_UNLOAD:
  706 
  707                 /*
  708                  * Note that the base code won't try to unload us until
  709                  * all nodes have been removed, and that can't happen
  710                  * until all Ethernet interfaces are removed. In any
  711                  * case, we know there are no nodes left if the action
  712                  * is MOD_UNLOAD, so there's no need to detach any nodes.
  713                  */
  714 
  715                 /* Unregister function hooks */
  716                 ng_ether_attach_p = NULL;
  717                 ng_ether_detach_p = NULL;
  718                 ng_ether_output_p = NULL;
  719                 ng_ether_input_p = NULL;
  720                 ng_ether_input_orphan_p = NULL;
  721                 break;
  722 
  723         default:
  724                 error = EOPNOTSUPP;
  725                 break;
  726         }
  727         splx(s);
  728         return (error);
  729 }
  730 

Cache object: ad7794e55e502241d2925dd1fd5ce959


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