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 
    6 /*-
    7  * Copyright (c) 1996-2000 Whistle Communications, Inc.
    8  * All rights reserved.
    9  * 
   10  * Subject to the following obligations and disclaimer of warranty, use and
   11  * redistribution of this software, in source or object code forms, with or
   12  * without modifications are expressly permitted by Whistle Communications;
   13  * provided, however, that:
   14  * 1. Any and all reproductions of the source or object code must include the
   15  *    copyright notice above and the following disclaimer of warranties; and
   16  * 2. No rights are granted, in any manner or form, to use Whistle
   17  *    Communications, Inc. trademarks, including the mark "WHISTLE
   18  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   19  *    such appears in the above copyright notice or in the software.
   20  * 
   21  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   22  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   23  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   24  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   26  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   27  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   28  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   29  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   30  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   31  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   32  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   33  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   36  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   37  * OF SUCH DAMAGE.
   38  *
   39  * Authors: Archie Cobbs <archie@freebsd.org>
   40  *          Julian Elischer <julian@freebsd.org>
   41  *
   42  * $FreeBSD: releng/9.0/sys/netgraph/ng_ether.c 224307 2011-07-25 09:12:48Z avg $
   43  */
   44 
   45 /*
   46  * ng_ether(4) netgraph node type
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/malloc.h>
   53 #include <sys/mbuf.h>
   54 #include <sys/errno.h>
   55 #include <sys/proc.h>
   56 #include <sys/syslog.h>
   57 #include <sys/socket.h>
   58 #include <sys/taskqueue.h>
   59 
   60 #include <net/if.h>
   61 #include <net/if_dl.h>
   62 #include <net/if_types.h>
   63 #include <net/if_arp.h>
   64 #include <net/if_var.h>
   65 #include <net/ethernet.h>
   66 #include <net/if_bridgevar.h>
   67 #include <net/vnet.h>
   68 
   69 #include <netgraph/ng_message.h>
   70 #include <netgraph/netgraph.h>
   71 #include <netgraph/ng_parse.h>
   72 #include <netgraph/ng_ether.h>
   73 
   74 #define IFP2NG(ifp)  (IFP2AC((ifp))->ac_netgraph)
   75 
   76 /* Per-node private data */
   77 struct private {
   78         struct ifnet    *ifp;           /* associated interface */
   79         hook_p          upper;          /* upper hook connection */
   80         hook_p          lower;          /* lower hook connection */
   81         hook_p          orphan;         /* orphan hook connection */
   82         u_char          autoSrcAddr;    /* always overwrite source address */
   83         u_char          promisc;        /* promiscuous mode enabled */
   84         u_long          hwassist;       /* hardware checksum capabilities */
   85         u_int           flags;          /* flags e.g. really die */
   86 };
   87 typedef struct private *priv_p;
   88 
   89 /* Hook pointers used by if_ethersubr.c to callback to netgraph */
   90 extern  void    (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
   91 extern  void    (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
   92 extern  int     (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
   93 extern  void    (*ng_ether_attach_p)(struct ifnet *ifp);
   94 extern  void    (*ng_ether_detach_p)(struct ifnet *ifp);
   95 extern  void    (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
   96 
   97 /* Functional hooks called from if_ethersubr.c */
   98 static void     ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
   99 static void     ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
  100 static int      ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
  101 static void     ng_ether_attach(struct ifnet *ifp);
  102 static void     ng_ether_detach(struct ifnet *ifp); 
  103 static void     ng_ether_link_state(struct ifnet *ifp, int state); 
  104 
  105 /* Other functions */
  106 static int      ng_ether_rcv_lower(hook_p node, item_p item);
  107 static int      ng_ether_rcv_upper(hook_p node, item_p item);
  108 
  109 /* Netgraph node methods */
  110 static ng_constructor_t ng_ether_constructor;
  111 static ng_rcvmsg_t      ng_ether_rcvmsg;
  112 static ng_shutdown_t    ng_ether_shutdown;
  113 static ng_newhook_t     ng_ether_newhook;
  114 static ng_rcvdata_t     ng_ether_rcvdata;
  115 static ng_disconnect_t  ng_ether_disconnect;
  116 static int              ng_ether_mod_event(module_t mod, int event, void *data);
  117 
  118 /* List of commands and how to convert arguments to/from ASCII */
  119 static const struct ng_cmdlist ng_ether_cmdlist[] = {
  120         {
  121           NGM_ETHER_COOKIE,
  122           NGM_ETHER_GET_IFNAME,
  123           "getifname",
  124           NULL,
  125           &ng_parse_string_type
  126         },
  127         {
  128           NGM_ETHER_COOKIE,
  129           NGM_ETHER_GET_IFINDEX,
  130           "getifindex",
  131           NULL,
  132           &ng_parse_int32_type
  133         },
  134         {
  135           NGM_ETHER_COOKIE,
  136           NGM_ETHER_GET_ENADDR,
  137           "getenaddr",
  138           NULL,
  139           &ng_parse_enaddr_type
  140         },
  141         {
  142           NGM_ETHER_COOKIE,
  143           NGM_ETHER_SET_ENADDR,
  144           "setenaddr",
  145           &ng_parse_enaddr_type,
  146           NULL
  147         },
  148         {
  149           NGM_ETHER_COOKIE,
  150           NGM_ETHER_GET_PROMISC,
  151           "getpromisc",
  152           NULL,
  153           &ng_parse_int32_type
  154         },
  155         {
  156           NGM_ETHER_COOKIE,
  157           NGM_ETHER_SET_PROMISC,
  158           "setpromisc",
  159           &ng_parse_int32_type,
  160           NULL
  161         },
  162         {
  163           NGM_ETHER_COOKIE,
  164           NGM_ETHER_GET_AUTOSRC,
  165           "getautosrc",
  166           NULL,
  167           &ng_parse_int32_type
  168         },
  169         {
  170           NGM_ETHER_COOKIE,
  171           NGM_ETHER_SET_AUTOSRC,
  172           "setautosrc",
  173           &ng_parse_int32_type,
  174           NULL
  175         },
  176         {
  177           NGM_ETHER_COOKIE,
  178           NGM_ETHER_ADD_MULTI,
  179           "addmulti",
  180           &ng_parse_enaddr_type,
  181           NULL
  182         },
  183         {
  184           NGM_ETHER_COOKIE,
  185           NGM_ETHER_DEL_MULTI,
  186           "delmulti",
  187           &ng_parse_enaddr_type,
  188           NULL
  189         },
  190         {
  191           NGM_ETHER_COOKIE,
  192           NGM_ETHER_DETACH,
  193           "detach",
  194           NULL,
  195           NULL
  196         },
  197         { 0 }
  198 };
  199 
  200 static struct ng_type ng_ether_typestruct = {
  201         .version =      NG_ABI_VERSION,
  202         .name =         NG_ETHER_NODE_TYPE,
  203         .mod_event =    ng_ether_mod_event,
  204         .constructor =  ng_ether_constructor,
  205         .rcvmsg =       ng_ether_rcvmsg,
  206         .shutdown =     ng_ether_shutdown,
  207         .newhook =      ng_ether_newhook,
  208         .rcvdata =      ng_ether_rcvdata,
  209         .disconnect =   ng_ether_disconnect,
  210         .cmdlist =      ng_ether_cmdlist,
  211 };
  212 NETGRAPH_INIT(ether, &ng_ether_typestruct);
  213 
  214 /******************************************************************
  215                     ETHERNET FUNCTION HOOKS
  216 ******************************************************************/
  217 
  218 /*
  219  * Handle a packet that has come in on an interface. We get to
  220  * look at it here before any upper layer protocols do.
  221  *
  222  * NOTE: this function will get called at splimp()
  223  */
  224 static void
  225 ng_ether_input(struct ifnet *ifp, struct mbuf **mp)
  226 {
  227         const node_p node = IFP2NG(ifp);
  228         const priv_p priv = NG_NODE_PRIVATE(node);
  229         int error;
  230 
  231         /* If "lower" hook not connected, let packet continue */
  232         if (priv->lower == NULL)
  233                 return;
  234         NG_SEND_DATA_ONLY(error, priv->lower, *mp);     /* sets *mp = NULL */
  235 }
  236 
  237 /*
  238  * Handle a packet that has come in on an interface, and which
  239  * does not match any of our known protocols (an ``orphan'').
  240  *
  241  * NOTE: this function will get called at splimp()
  242  */
  243 static void
  244 ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m)
  245 {
  246         const node_p node = IFP2NG(ifp);
  247         const priv_p priv = NG_NODE_PRIVATE(node);
  248         int error;
  249 
  250         /* If "orphan" hook not connected, discard packet */
  251         if (priv->orphan == NULL) {
  252                 m_freem(m);
  253                 return;
  254         }
  255         NG_SEND_DATA_ONLY(error, priv->orphan, m);
  256 }
  257 
  258 /*
  259  * Handle a packet that is going out on an interface.
  260  * The Ethernet header is already attached to the mbuf.
  261  */
  262 static int
  263 ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
  264 {
  265         const node_p node = IFP2NG(ifp);
  266         const priv_p priv = NG_NODE_PRIVATE(node);
  267         int error = 0;
  268 
  269         /* If "upper" hook not connected, let packet continue */
  270         if (priv->upper == NULL)
  271                 return (0);
  272 
  273         /* Send it out "upper" hook */
  274         NG_OUTBOUND_THREAD_REF();
  275         NG_SEND_DATA_ONLY(error, priv->upper, *mp);
  276         NG_OUTBOUND_THREAD_UNREF();
  277         return (error);
  278 }
  279 
  280 /*
  281  * A new Ethernet interface has been attached.
  282  * Create a new node for it, etc.
  283  */
  284 static void
  285 ng_ether_attach(struct ifnet *ifp)
  286 {
  287         priv_p priv;
  288         node_p node;
  289 
  290         /*
  291          * Do not create / attach an ether node to this ifnet if
  292          * a netgraph node with the same name already exists.
  293          * This should prevent ether nodes to become attached to
  294          * eiface nodes, which may be problematic due to naming
  295          * clashes.
  296          */
  297         if ((node = ng_name2noderef(NULL, ifp->if_xname)) != NULL) {
  298                 NG_NODE_UNREF(node);
  299                 return;
  300         }
  301 
  302         /* Create node */
  303         KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
  304         if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
  305                 log(LOG_ERR, "%s: can't %s for %s\n",
  306                     __func__, "create node", ifp->if_xname);
  307                 return;
  308         }
  309 
  310         /* Allocate private data */
  311         priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
  312         if (priv == NULL) {
  313                 log(LOG_ERR, "%s: can't %s for %s\n",
  314                     __func__, "allocate memory", ifp->if_xname);
  315                 NG_NODE_UNREF(node);
  316                 return;
  317         }
  318         NG_NODE_SET_PRIVATE(node, priv);
  319         priv->ifp = ifp;
  320         IFP2NG(ifp) = node;
  321         priv->hwassist = ifp->if_hwassist;
  322 
  323         /* Try to give the node the same name as the interface */
  324         if (ng_name_node(node, ifp->if_xname) != 0) {
  325                 log(LOG_WARNING, "%s: can't name node %s\n",
  326                     __func__, ifp->if_xname);
  327         }
  328 }
  329 
  330 /*
  331  * An Ethernet interface is being detached.
  332  * REALLY Destroy its node.
  333  */
  334 static void
  335 ng_ether_detach(struct ifnet *ifp)
  336 {
  337         const node_p node = IFP2NG(ifp);
  338         const priv_p priv = NG_NODE_PRIVATE(node);
  339 
  340         taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
  341         NG_NODE_REALLY_DIE(node);       /* Force real removal of node */
  342         /*
  343          * We can't assume the ifnet is still around when we run shutdown
  344          * So zap it now. XXX We HOPE that anything running at this time
  345          * handles it (as it should in the non netgraph case).
  346          */
  347         IFP2NG(ifp) = NULL;
  348         priv->ifp = NULL;       /* XXX race if interrupted an output packet */
  349         ng_rmnode_self(node);           /* remove all netgraph parts */
  350 }
  351 
  352 /*
  353  * Notify graph about link event.
  354  * if_link_state_change() has already checked that the state has changed.
  355  */
  356 static void
  357 ng_ether_link_state(struct ifnet *ifp, int state)
  358 {
  359         const node_p node = IFP2NG(ifp);
  360         const priv_p priv = NG_NODE_PRIVATE(node);
  361         struct ng_mesg *msg;
  362         int cmd, dummy_error = 0;
  363 
  364         if (state == LINK_STATE_UP)
  365                 cmd = NGM_LINK_IS_UP;
  366         else if (state == LINK_STATE_DOWN)
  367                 cmd = NGM_LINK_IS_DOWN;
  368         else
  369                 return;
  370 
  371         if (priv->lower != NULL) {
  372                 NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT);
  373                 if (msg != NULL)
  374                         NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0);
  375         }
  376         if (priv->orphan != NULL) {
  377                 NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT);
  378                 if (msg != NULL)
  379                         NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->orphan, 0);
  380         }
  381 }
  382 
  383 /******************************************************************
  384                     NETGRAPH NODE METHODS
  385 ******************************************************************/
  386 
  387 /*
  388  * It is not possible or allowable to create a node of this type.
  389  * Nodes get created when the interface is attached (or, when
  390  * this node type's KLD is loaded).
  391  */
  392 static int
  393 ng_ether_constructor(node_p node)
  394 {
  395         return (EINVAL);
  396 }
  397 
  398 /*
  399  * Check for attaching a new hook.
  400  */
  401 static  int
  402 ng_ether_newhook(node_p node, hook_p hook, const char *name)
  403 {
  404         const priv_p priv = NG_NODE_PRIVATE(node);
  405         hook_p *hookptr;
  406 
  407         /* Divert hook is an alias for lower */
  408         if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
  409                 name = NG_ETHER_HOOK_LOWER;
  410 
  411         /* Which hook? */
  412         if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) {
  413                 hookptr = &priv->upper;
  414                 NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_upper);
  415                 NG_HOOK_SET_TO_INBOUND(hook);
  416         } else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) {
  417                 hookptr = &priv->lower;
  418                 NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_lower);
  419         } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) {
  420                 hookptr = &priv->orphan;
  421                 NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_lower);
  422         } else
  423                 return (EINVAL);
  424 
  425         /* Check if already connected (shouldn't be, but doesn't hurt) */
  426         if (*hookptr != NULL)
  427                 return (EISCONN);
  428 
  429         /* Disable hardware checksums while 'upper' hook is connected */
  430         if (hookptr == &priv->upper)
  431                 priv->ifp->if_hwassist = 0;
  432         NG_HOOK_HI_STACK(hook);
  433         /* OK */
  434         *hookptr = hook;
  435         return (0);
  436 }
  437 
  438 /*
  439  * Receive an incoming control message.
  440  */
  441 static int
  442 ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
  443 {
  444         const priv_p priv = NG_NODE_PRIVATE(node);
  445         struct ng_mesg *resp = NULL;
  446         int error = 0;
  447         struct ng_mesg *msg;
  448 
  449         NGI_GET_MSG(item, msg);
  450         switch (msg->header.typecookie) {
  451         case NGM_ETHER_COOKIE:
  452                 switch (msg->header.cmd) {
  453                 case NGM_ETHER_GET_IFNAME:
  454                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
  455                         if (resp == NULL) {
  456                                 error = ENOMEM;
  457                                 break;
  458                         }
  459                         strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
  460                         break;
  461                 case NGM_ETHER_GET_IFINDEX:
  462                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  463                         if (resp == NULL) {
  464                                 error = ENOMEM;
  465                                 break;
  466                         }
  467                         *((u_int32_t *)resp->data) = priv->ifp->if_index;
  468                         break;
  469                 case NGM_ETHER_GET_ENADDR:
  470                         NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT);
  471                         if (resp == NULL) {
  472                                 error = ENOMEM;
  473                                 break;
  474                         }
  475                         bcopy(IF_LLADDR(priv->ifp),
  476                             resp->data, ETHER_ADDR_LEN);
  477                         break;
  478                 case NGM_ETHER_SET_ENADDR:
  479                     {
  480                         if (msg->header.arglen != ETHER_ADDR_LEN) {
  481                                 error = EINVAL;
  482                                 break;
  483                         }
  484                         error = if_setlladdr(priv->ifp,
  485                             (u_char *)msg->data, ETHER_ADDR_LEN);
  486                         EVENTHANDLER_INVOKE(iflladdr_event, priv->ifp);
  487                         break;
  488                     }
  489                 case NGM_ETHER_GET_PROMISC:
  490                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  491                         if (resp == NULL) {
  492                                 error = ENOMEM;
  493                                 break;
  494                         }
  495                         *((u_int32_t *)resp->data) = priv->promisc;
  496                         break;
  497                 case NGM_ETHER_SET_PROMISC:
  498                     {
  499                         u_char want;
  500 
  501                         if (msg->header.arglen != sizeof(u_int32_t)) {
  502                                 error = EINVAL;
  503                                 break;
  504                         }
  505                         want = !!*((u_int32_t *)msg->data);
  506                         if (want ^ priv->promisc) {
  507                                 if ((error = ifpromisc(priv->ifp, want)) != 0)
  508                                         break;
  509                                 priv->promisc = want;
  510                         }
  511                         break;
  512                     }
  513                 case NGM_ETHER_GET_AUTOSRC:
  514                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
  515                         if (resp == NULL) {
  516                                 error = ENOMEM;
  517                                 break;
  518                         }
  519                         *((u_int32_t *)resp->data) = priv->autoSrcAddr;
  520                         break;
  521                 case NGM_ETHER_SET_AUTOSRC:
  522                         if (msg->header.arglen != sizeof(u_int32_t)) {
  523                                 error = EINVAL;
  524                                 break;
  525                         }
  526                         priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
  527                         break;
  528                 case NGM_ETHER_ADD_MULTI:
  529                     {
  530                         struct sockaddr_dl sa_dl;
  531                         struct ifmultiaddr *ifma;
  532 
  533                         if (msg->header.arglen != ETHER_ADDR_LEN) {
  534                                 error = EINVAL;
  535                                 break;
  536                         }
  537                         bzero(&sa_dl, sizeof(struct sockaddr_dl));
  538                         sa_dl.sdl_len = sizeof(struct sockaddr_dl);
  539                         sa_dl.sdl_family = AF_LINK;
  540                         sa_dl.sdl_alen = ETHER_ADDR_LEN;
  541                         bcopy((void *)msg->data, LLADDR(&sa_dl),
  542                             ETHER_ADDR_LEN);
  543                         /*
  544                          * Netgraph is only permitted to join groups once
  545                          * via the if_addmulti() KPI, because it cannot hold
  546                          * struct ifmultiaddr * between calls. It may also
  547                          * lose a race while we check if the membership
  548                          * already exists.
  549                          */
  550                         if_maddr_rlock(priv->ifp);
  551                         ifma = if_findmulti(priv->ifp,
  552                             (struct sockaddr *)&sa_dl);
  553                         if_maddr_runlock(priv->ifp);
  554                         if (ifma != NULL) {
  555                                 error = EADDRINUSE;
  556                         } else {
  557                                 error = if_addmulti(priv->ifp,
  558                                     (struct sockaddr *)&sa_dl, &ifma);
  559                         }
  560                         break;
  561                     }
  562                 case NGM_ETHER_DEL_MULTI:
  563                     {
  564                         struct sockaddr_dl sa_dl;
  565 
  566                         if (msg->header.arglen != ETHER_ADDR_LEN) {
  567                                 error = EINVAL;
  568                                 break;
  569                         }
  570                         bzero(&sa_dl, sizeof(struct sockaddr_dl));
  571                         sa_dl.sdl_len = sizeof(struct sockaddr_dl);
  572                         sa_dl.sdl_family = AF_LINK;
  573                         sa_dl.sdl_alen = ETHER_ADDR_LEN;
  574                         bcopy((void *)msg->data, LLADDR(&sa_dl),
  575                             ETHER_ADDR_LEN);
  576                         error = if_delmulti(priv->ifp,
  577                             (struct sockaddr *)&sa_dl);
  578                         break;
  579                     }
  580                 case NGM_ETHER_DETACH:
  581                         ng_ether_detach(priv->ifp);
  582                         break;
  583                 default:
  584                         error = EINVAL;
  585                         break;
  586                 }
  587                 break;
  588         default:
  589                 error = EINVAL;
  590                 break;
  591         }
  592         NG_RESPOND_MSG(error, node, item, resp);
  593         NG_FREE_MSG(msg);
  594         return (error);
  595 }
  596 
  597 /*
  598  * Receive data on a hook.
  599  * Since we use per-hook recveive methods this should never be called.
  600  */
  601 static int
  602 ng_ether_rcvdata(hook_p hook, item_p item)
  603 {
  604         NG_FREE_ITEM(item);
  605 
  606         panic("%s: weird hook", __func__);
  607 }
  608 
  609 /*
  610  * Handle an mbuf received on the "lower" or "orphan" hook.
  611  */
  612 static int
  613 ng_ether_rcv_lower(hook_p hook, item_p item)
  614 {
  615         struct mbuf *m;
  616         const node_p node = NG_HOOK_NODE(hook);
  617         const priv_p priv = NG_NODE_PRIVATE(node);
  618         struct ifnet *const ifp = priv->ifp;
  619 
  620         NGI_GET_M(item, m);
  621         NG_FREE_ITEM(item);
  622 
  623         /* Check whether interface is ready for packets */
  624 
  625         if (!((ifp->if_flags & IFF_UP) &&
  626             (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
  627                 NG_FREE_M(m);
  628                 return (ENETDOWN);
  629         }
  630 
  631         /* Make sure header is fully pulled up */
  632         if (m->m_pkthdr.len < sizeof(struct ether_header)) {
  633                 NG_FREE_M(m);
  634                 return (EINVAL);
  635         }
  636         if (m->m_len < sizeof(struct ether_header)
  637             && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
  638                 return (ENOBUFS);
  639 
  640         /* Drop in the MAC address if desired */
  641         if (priv->autoSrcAddr) {
  642 
  643                 /* Make the mbuf writable if it's not already */
  644                 if (!M_WRITABLE(m)
  645                     && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
  646                         return (ENOBUFS);
  647 
  648                 /* Overwrite source MAC address */
  649                 bcopy(IF_LLADDR(ifp),
  650                     mtod(m, struct ether_header *)->ether_shost,
  651                     ETHER_ADDR_LEN);
  652         }
  653 
  654         /* Send it on its way */
  655         return ether_output_frame(ifp, m);
  656 }
  657 
  658 /*
  659  * Handle an mbuf received on the "upper" hook.
  660  */
  661 static int
  662 ng_ether_rcv_upper(hook_p hook, item_p item)
  663 {
  664         struct mbuf *m;
  665         const node_p node = NG_HOOK_NODE(hook);
  666         const priv_p priv = NG_NODE_PRIVATE(node);
  667         struct ifnet *ifp = priv->ifp;
  668 
  669         NGI_GET_M(item, m);
  670         NG_FREE_ITEM(item);
  671 
  672         /* Check length and pull off header */
  673         if (m->m_pkthdr.len < sizeof(struct ether_header)) {
  674                 NG_FREE_M(m);
  675                 return (EINVAL);
  676         }
  677         if (m->m_len < sizeof(struct ether_header) &&
  678             (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
  679                 return (ENOBUFS);
  680 
  681         m->m_pkthdr.rcvif = ifp;
  682 
  683         /* Pass the packet to the bridge, it may come back to us */
  684         if (ifp->if_bridge) {
  685                 BRIDGE_INPUT(ifp, m);
  686                 if (m == NULL)
  687                         return (0);
  688         }
  689 
  690         /* Route packet back in */
  691         ether_demux(ifp, m);
  692         return (0);
  693 }
  694 
  695 /*
  696  * Shutdown node. This resets the node but does not remove it
  697  * unless the REALLY_DIE flag is set.
  698  */
  699 static int
  700 ng_ether_shutdown(node_p node)
  701 {
  702         const priv_p priv = NG_NODE_PRIVATE(node);
  703 
  704         if (node->nd_flags & NGF_REALLY_DIE) {
  705                 /*
  706                  * WE came here because the ethernet card is being unloaded,
  707                  * so stop being persistant.
  708                  * Actually undo all the things we did on creation.
  709                  * Assume the ifp has already been freed.
  710                  */
  711                 NG_NODE_SET_PRIVATE(node, NULL);
  712                 free(priv, M_NETGRAPH);         
  713                 NG_NODE_UNREF(node);    /* free node itself */
  714                 return (0);
  715         }
  716         if (priv->promisc) {            /* disable promiscuous mode */
  717                 (void)ifpromisc(priv->ifp, 0);
  718                 priv->promisc = 0;
  719         }
  720         NG_NODE_REVIVE(node);           /* Signal ng_rmnode we are persisant */
  721 
  722         return (0);
  723 }
  724 
  725 /*
  726  * Hook disconnection.
  727  */
  728 static int
  729 ng_ether_disconnect(hook_p hook)
  730 {
  731         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  732 
  733         if (hook == priv->upper) {
  734                 priv->upper = NULL;
  735                 if (priv->ifp != NULL)          /* restore h/w csum */
  736                         priv->ifp->if_hwassist = priv->hwassist;
  737         } else if (hook == priv->lower)
  738                 priv->lower = NULL;
  739         else if (hook == priv->orphan)
  740                 priv->orphan = NULL;
  741         else
  742                 panic("%s: weird hook", __func__);
  743         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
  744         && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
  745                 ng_rmnode_self(NG_HOOK_NODE(hook));     /* reset node */
  746         return (0);
  747 }
  748 
  749 /******************************************************************
  750                         INITIALIZATION
  751 ******************************************************************/
  752 
  753 /*
  754  * Handle loading and unloading for this node type.
  755  */
  756 static int
  757 ng_ether_mod_event(module_t mod, int event, void *data)
  758 {
  759         int error = 0;
  760         int s;
  761 
  762         s = splnet();
  763         switch (event) {
  764         case MOD_LOAD:
  765 
  766                 /* Register function hooks */
  767                 if (ng_ether_attach_p != NULL) {
  768                         error = EEXIST;
  769                         break;
  770                 }
  771                 ng_ether_attach_p = ng_ether_attach;
  772                 ng_ether_detach_p = ng_ether_detach;
  773                 ng_ether_output_p = ng_ether_output;
  774                 ng_ether_input_p = ng_ether_input;
  775                 ng_ether_input_orphan_p = ng_ether_input_orphan;
  776                 ng_ether_link_state_p = ng_ether_link_state;
  777 
  778                 break;
  779 
  780         case MOD_UNLOAD:
  781 
  782                 /*
  783                  * Note that the base code won't try to unload us until
  784                  * all nodes have been removed, and that can't happen
  785                  * until all Ethernet interfaces are removed. In any
  786                  * case, we know there are no nodes left if the action
  787                  * is MOD_UNLOAD, so there's no need to detach any nodes.
  788                  */
  789 
  790                 /* Unregister function hooks */
  791                 ng_ether_attach_p = NULL;
  792                 ng_ether_detach_p = NULL;
  793                 ng_ether_output_p = NULL;
  794                 ng_ether_input_p = NULL;
  795                 ng_ether_input_orphan_p = NULL;
  796                 ng_ether_link_state_p = NULL;
  797                 break;
  798 
  799         default:
  800                 error = EOPNOTSUPP;
  801                 break;
  802         }
  803         splx(s);
  804         return (error);
  805 }
  806 
  807 static void
  808 vnet_ng_ether_init(const void *unused)
  809 {
  810         struct ifnet *ifp;
  811 
  812         /* If module load was rejected, don't attach to vnets. */
  813         if (ng_ether_attach_p != ng_ether_attach)
  814                 return;
  815 
  816         /* Create nodes for any already-existing Ethernet interfaces. */
  817         IFNET_RLOCK();
  818         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
  819                 if (ifp->if_type == IFT_ETHER
  820                     || ifp->if_type == IFT_L2VLAN)
  821                         ng_ether_attach(ifp);
  822         }
  823         IFNET_RUNLOCK();
  824 }
  825 VNET_SYSINIT(vnet_ng_ether_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
  826     vnet_ng_ether_init, NULL);

Cache object: 69dc3bbf1e63bdbeeff1e3f869d20f47


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