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/atm/ng_atm.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  * Copyright (c) 2001-2003
    3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
    4  *      All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * Author: Hartmut Brandt <harti@freebsd.org>
   28  */
   29 
   30 /*
   31  * Netgraph module to connect NATM interfaces to netgraph.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/11.1/sys/netgraph/atm/ng_atm.c 298813 2016-04-29 21:25:05Z pfg $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/errno.h>
   43 #include <sys/syslog.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/sbuf.h>
   47 #include <sys/ioccom.h>
   48 #include <sys/sysctl.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_types.h>
   52 #include <net/if_arp.h>
   53 #include <net/if_var.h>
   54 #include <net/if_media.h>
   55 #include <net/if_atm.h>
   56 #include <net/vnet.h>
   57 
   58 #include <netgraph/ng_message.h>
   59 #include <netgraph/netgraph.h>
   60 #include <netgraph/ng_parse.h>
   61 #include <netgraph/atm/ng_atm.h>
   62 
   63 /*
   64  * Hooks in the NATM code
   65  */
   66 extern void     (*ng_atm_attach_p)(struct ifnet *);
   67 extern void     (*ng_atm_detach_p)(struct ifnet *);
   68 extern int      (*ng_atm_output_p)(struct ifnet *, struct mbuf **);
   69 extern void     (*ng_atm_input_p)(struct ifnet *, struct mbuf **,
   70                     struct atm_pseudohdr *, void *);
   71 extern void     (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
   72                     struct atm_pseudohdr *, void *);
   73 extern void     (*ng_atm_event_p)(struct ifnet *, uint32_t, void *);
   74 
   75 /*
   76  * Sysctl stuff.
   77  */
   78 static SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0,
   79     "atm related stuff");
   80 
   81 #ifdef NGATM_DEBUG
   82 static int allow_shutdown;
   83 
   84 SYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
   85     &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
   86 #endif
   87 
   88 /*
   89  * Hook private data
   90  */
   91 struct ngvcc {
   92         uint16_t        vpi;    /* VPI of this hook */
   93         uint16_t        vci;    /* VCI of this hook, 0 if none */
   94         uint32_t        flags;  /* private flags */
   95         hook_p          hook;   /* the connected hook */
   96 
   97         LIST_ENTRY(ngvcc) link;
   98 };
   99 #define VCC_OPEN        0x0001  /* open */
  100 
  101 /*
  102  * Node private data
  103  */
  104 struct priv {
  105         struct ifnet    *ifp;           /* the ATM interface */
  106         hook_p          input;          /* raw input hook */
  107         hook_p          orphans;        /* packets to nowhere */
  108         hook_p          output;         /* catch output packets */
  109         hook_p          manage;         /* has also entry in vccs */
  110         uint64_t        in_packets;
  111         uint64_t        in_errors;
  112         uint64_t        out_packets;
  113         uint64_t        out_errors;
  114 
  115         LIST_HEAD(, ngvcc) vccs;
  116 };
  117 
  118 /*
  119  * Parse ifstate state
  120  */
  121 static const struct ng_parse_struct_field ng_atm_if_change_info[] =
  122     NGM_ATM_IF_CHANGE_INFO;
  123 static const struct ng_parse_type ng_atm_if_change_type = {
  124         &ng_parse_struct_type,
  125         &ng_atm_if_change_info
  126 };
  127 
  128 /*
  129  * Parse vcc state change
  130  */
  131 static const struct ng_parse_struct_field ng_atm_vcc_change_info[] =
  132     NGM_ATM_VCC_CHANGE_INFO;
  133 static const struct ng_parse_type ng_atm_vcc_change_type = {
  134         &ng_parse_struct_type,
  135         &ng_atm_vcc_change_info
  136 };
  137 
  138 /*
  139  * Parse acr change
  140  */
  141 static const struct ng_parse_struct_field ng_atm_acr_change_info[] =
  142     NGM_ATM_ACR_CHANGE_INFO;
  143 static const struct ng_parse_type ng_atm_acr_change_type = {
  144         &ng_parse_struct_type,
  145         &ng_atm_acr_change_info
  146 };
  147 
  148 /*
  149  * Parse the configuration structure ng_atm_config
  150  */
  151 static const struct ng_parse_struct_field ng_atm_config_type_info[] =
  152     NGM_ATM_CONFIG_INFO;
  153 
  154 static const struct ng_parse_type ng_atm_config_type = {
  155         &ng_parse_struct_type,
  156         &ng_atm_config_type_info
  157 };
  158 
  159 /*
  160  * Parse a single vcc structure and a variable array of these ng_atm_vccs
  161  */
  162 static const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
  163     NGM_ATM_TPARAM_INFO;
  164 static const struct ng_parse_type ng_atm_tparam_type = {
  165         &ng_parse_struct_type,
  166         &ng_atm_tparam_type_info
  167 };
  168 static const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
  169     NGM_ATM_VCC_INFO;
  170 static const struct ng_parse_type ng_atm_vcc_type = {
  171         &ng_parse_struct_type,
  172         &ng_atm_vcc_type_info
  173 };
  174 
  175 
  176 static int
  177 ng_atm_vccarray_getlen(const struct ng_parse_type *type,
  178         const u_char *start, const u_char *buf)
  179 {
  180         const struct atmio_vcctable *vp;
  181 
  182         vp = (const struct atmio_vcctable *)
  183             (buf - offsetof(struct atmio_vcctable, vccs));
  184 
  185         return (vp->count);
  186 }
  187 static const struct ng_parse_array_info ng_atm_vccarray_info =
  188     NGM_ATM_VCCARRAY_INFO;
  189 static const struct ng_parse_type ng_atm_vccarray_type = {
  190         &ng_parse_array_type,
  191         &ng_atm_vccarray_info
  192 };
  193 
  194 
  195 static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
  196     NGM_ATM_VCCTABLE_INFO;
  197 
  198 static const struct ng_parse_type ng_atm_vcctable_type = {
  199         &ng_parse_struct_type,
  200         &ng_atm_vcctable_type_info
  201 };
  202 
  203 /*
  204  * Parse CPCS INIT structure ng_atm_cpcs_init
  205  */
  206 static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
  207     NGM_ATM_CPCS_INIT_INFO;
  208 
  209 static const struct ng_parse_type ng_atm_cpcs_init_type = {
  210         &ng_parse_struct_type,
  211         &ng_atm_cpcs_init_type_info
  212 };
  213 
  214 /*
  215  * Parse CPCS TERM structure ng_atm_cpcs_term
  216  */
  217 static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
  218     NGM_ATM_CPCS_TERM_INFO;
  219 
  220 static const struct ng_parse_type ng_atm_cpcs_term_type = {
  221         &ng_parse_struct_type,
  222         &ng_atm_cpcs_term_type_info
  223 };
  224 
  225 /*
  226  * Parse statistic struct
  227  */
  228 static const struct ng_parse_struct_field ng_atm_stats_type_info[] =
  229     NGM_ATM_STATS_INFO;
  230 
  231 static const struct ng_parse_type ng_atm_stats_type = {
  232         &ng_parse_struct_type,
  233         &ng_atm_stats_type_info
  234 };
  235 
  236 static const struct ng_cmdlist ng_atm_cmdlist[] = {
  237         {
  238           NGM_ATM_COOKIE,
  239           NGM_ATM_GET_IFNAME,
  240           "getifname",
  241           NULL,
  242           &ng_parse_string_type
  243         },
  244         {
  245           NGM_ATM_COOKIE,
  246           NGM_ATM_GET_CONFIG,
  247           "getconfig",
  248           NULL,
  249           &ng_atm_config_type
  250         },
  251         {
  252           NGM_ATM_COOKIE,
  253           NGM_ATM_GET_VCCS,
  254           "getvccs",
  255           NULL,
  256           &ng_atm_vcctable_type
  257         },
  258         {
  259           NGM_ATM_COOKIE,
  260           NGM_ATM_CPCS_INIT,
  261           "cpcsinit",
  262           &ng_atm_cpcs_init_type,
  263           NULL
  264         },
  265         {
  266           NGM_ATM_COOKIE,
  267           NGM_ATM_CPCS_TERM,
  268           "cpcsterm",
  269           &ng_atm_cpcs_term_type,
  270           NULL
  271         },
  272         {
  273           NGM_ATM_COOKIE,
  274           NGM_ATM_GET_VCC,
  275           "getvcc",
  276           &ng_parse_hookbuf_type,
  277           &ng_atm_vcc_type
  278         },
  279         {
  280           NGM_ATM_COOKIE,
  281           NGM_ATM_GET_VCCID,
  282           "getvccid",
  283           &ng_atm_vcc_type,
  284           &ng_atm_vcc_type
  285         },
  286         {
  287           NGM_ATM_COOKIE,
  288           NGM_ATM_GET_STATS,
  289           "getstats",
  290           NULL,
  291           &ng_atm_stats_type
  292         },
  293 
  294         /* events */
  295         {
  296           NGM_ATM_COOKIE,
  297           NGM_ATM_IF_CHANGE,
  298           "if_change",
  299           &ng_atm_if_change_type,
  300           &ng_atm_if_change_type,
  301         },
  302         {
  303           NGM_ATM_COOKIE,
  304           NGM_ATM_VCC_CHANGE,
  305           "vcc_change",
  306           &ng_atm_vcc_change_type,
  307           &ng_atm_vcc_change_type,
  308         },
  309         {
  310           NGM_ATM_COOKIE,
  311           NGM_ATM_ACR_CHANGE,
  312           "acr_change",
  313           &ng_atm_acr_change_type,
  314           &ng_atm_acr_change_type,
  315         },
  316         { 0 }
  317 };
  318 
  319 static int ng_atm_mod_event(module_t, int, void *);
  320 
  321 static ng_constructor_t ng_atm_constructor;
  322 static ng_shutdown_t    ng_atm_shutdown;
  323 static ng_rcvmsg_t      ng_atm_rcvmsg;
  324 static ng_newhook_t     ng_atm_newhook;
  325 static ng_connect_t     ng_atm_connect;
  326 static ng_disconnect_t  ng_atm_disconnect;
  327 static ng_rcvdata_t     ng_atm_rcvdata;
  328 static ng_rcvdata_t     ng_atm_rcvdrop;
  329 
  330 static struct ng_type ng_atm_typestruct = {
  331         .version =      NG_ABI_VERSION,
  332         .name =         NG_ATM_NODE_TYPE,
  333         .mod_event =    ng_atm_mod_event,
  334         .constructor =  ng_atm_constructor,
  335         .rcvmsg =       ng_atm_rcvmsg,
  336         .shutdown =     ng_atm_shutdown,
  337         .newhook =      ng_atm_newhook,
  338         .connect =      ng_atm_connect,
  339         .rcvdata =      ng_atm_rcvdata,
  340         .disconnect =   ng_atm_disconnect,
  341         .cmdlist =      ng_atm_cmdlist,
  342 };
  343 NETGRAPH_INIT(atm, &ng_atm_typestruct);
  344 
  345 static const struct {
  346         u_int   media;
  347         const char *name;
  348 } atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
  349 
  350 
  351 #define IFP2NG(IFP)     ((node_p)((struct ifatm *)(IFP)->if_softc)->ngpriv)
  352 #define IFP2NG_SET(IFP, val)    (((struct ifatm *)(IFP)->if_softc)->ngpriv = (val))
  353 
  354 #define IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
  355                  "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
  356                  "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
  357                  "\015LINK0\016LINK1\017LINK2\020MULTICAST"
  358 
  359 
  360 /************************************************************/
  361 /*
  362  * INPUT
  363  */
  364 /*
  365  * A packet is received from an interface. 
  366  * If we have an input hook, prepend the pseudoheader to the data and
  367  * deliver it out to that hook. If not, look whether it is destined for
  368  * use. If so locate the appropriate hook, deliver the packet without the
  369  * header and we are done. If it is not for us, leave it alone.
  370  */
  371 static void
  372 ng_atm_input(struct ifnet *ifp, struct mbuf **mp,
  373         struct atm_pseudohdr *ah, void *rxhand)
  374 {
  375         node_p node = IFP2NG(ifp);
  376         struct priv *priv;
  377         const struct ngvcc *vcc;
  378         int error;
  379 
  380         if (node == NULL)
  381                 return;
  382         priv = NG_NODE_PRIVATE(node);
  383         if (priv->input != NULL) {
  384                 /*
  385                  * Prepend the atm_pseudoheader.
  386                  */
  387                 M_PREPEND(*mp, sizeof(*ah), M_NOWAIT);
  388                 if (*mp == NULL)
  389                         return;
  390                 memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
  391                 NG_SEND_DATA_ONLY(error, priv->input, *mp);
  392                 if (error == 0) {
  393                         priv->in_packets++;
  394                         *mp = NULL;
  395                 } else {
  396 #ifdef NGATM_DEBUG
  397                         printf("%s: error=%d\n", __func__, error);
  398 #endif
  399                         priv->in_errors++;
  400                 }
  401                 return;
  402         }
  403         if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
  404                 return;
  405 
  406         vcc = (struct ngvcc *)rxhand;
  407 
  408         NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
  409         if (error == 0) {
  410                 priv->in_packets++;
  411                 *mp = NULL;
  412         } else {
  413 #ifdef NGATM_DEBUG
  414                 printf("%s: error=%d\n", __func__, error);
  415 #endif
  416                 priv->in_errors++;
  417         }
  418 }
  419 
  420 /*
  421  * ATM packet is about to be output. The atm_pseudohdr is already prepended.
  422  * If the hook is set, reroute the packet to the hook.
  423  */
  424 static int
  425 ng_atm_output(struct ifnet *ifp, struct mbuf **mp)
  426 {
  427         const node_p node = IFP2NG(ifp);
  428         const struct priv *priv;
  429         int error = 0;
  430 
  431         if (node == NULL)
  432                 return (0);
  433         priv = NG_NODE_PRIVATE(node);
  434         if (priv->output) {
  435                 NG_SEND_DATA_ONLY(error, priv->output, *mp);
  436                 *mp = NULL;
  437         }
  438 
  439         return (error);
  440 }
  441 
  442 /*
  443  * Well, this doesn't make much sense for ATM.
  444  */
  445 static void
  446 ng_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
  447         struct atm_pseudohdr *ah, void *rxhand)
  448 {
  449         node_p node = IFP2NG(ifp);
  450         struct priv *priv;
  451         int error;
  452 
  453         if (node == NULL) {
  454                 m_freem(m);
  455                 return;
  456         }
  457         priv = NG_NODE_PRIVATE(node);
  458         if (priv->orphans == NULL) {
  459                 m_freem(m);
  460                 return;
  461         }
  462         /*
  463          * Prepend the atm_pseudoheader.
  464          */
  465         M_PREPEND(m, sizeof(*ah), M_NOWAIT);
  466         if (m == NULL)
  467                 return;
  468         memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
  469         NG_SEND_DATA_ONLY(error, priv->orphans, m);
  470         if (error == 0)
  471                 priv->in_packets++;
  472         else {
  473                 priv->in_errors++;
  474 #ifdef NGATM_DEBUG
  475                 printf("%s: error=%d\n", __func__, error);
  476 #endif
  477         }
  478 }
  479 
  480 /************************************************************/
  481 /*
  482  * OUTPUT
  483  */
  484 static int
  485 ng_atm_rcvdata(hook_p hook, item_p item)
  486 {
  487         node_p node = NG_HOOK_NODE(hook);
  488         struct priv *priv = NG_NODE_PRIVATE(node);
  489         const struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
  490         struct mbuf *m;
  491         struct atm_pseudohdr *aph;
  492         int error;
  493 
  494         if (vcc->vci == 0) {
  495                 NG_FREE_ITEM(item);
  496                 return (ENOTCONN);
  497         }
  498 
  499         NGI_GET_M(item, m);
  500         NG_FREE_ITEM(item);
  501 
  502         /*
  503          * Prepend pseudo-hdr. Drivers don't care about the flags.
  504          */
  505         M_PREPEND(m, sizeof(*aph), M_NOWAIT);
  506         if (m == NULL) {
  507                 NG_FREE_M(m);
  508                 return (ENOMEM);
  509         }
  510         aph = mtod(m, struct atm_pseudohdr *);
  511         ATM_PH_VPI(aph) = vcc->vpi;
  512         ATM_PH_SETVCI(aph, vcc->vci);
  513         ATM_PH_FLAGS(aph) = 0;
  514 
  515         if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
  516                 priv->out_packets++;
  517         else
  518                 priv->out_errors++;
  519         return (error);
  520 }
  521 
  522 static int
  523 ng_atm_rcvdrop(hook_p hook, item_p item)
  524 {
  525         NG_FREE_ITEM(item);
  526         return (0);
  527 }
  528 
  529 
  530 /************************************************************
  531  *
  532  * Event from driver.
  533  */
  534 static void
  535 ng_atm_event_func(node_p node, hook_p hook, void *arg, int event)
  536 {
  537         const struct priv *priv = NG_NODE_PRIVATE(node);
  538         struct ngvcc *vcc;
  539         struct ng_mesg *mesg;
  540         int error;
  541 
  542         switch (event) {
  543 
  544           case ATMEV_FLOW_CONTROL:
  545             {
  546                 struct atmev_flow_control *ev = arg;
  547                 struct ngm_queue_state *qstate;
  548 
  549                 /* find the connection */
  550                 LIST_FOREACH(vcc, &priv->vccs, link)
  551                         if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
  552                                 break;
  553                 if (vcc == NULL)
  554                         break;
  555 
  556                 /* convert into a flow control message */
  557                 NG_MKMESSAGE(mesg, NGM_FLOW_COOKIE,
  558                     ev->busy ? NGM_HIGH_WATER_PASSED : NGM_LOW_WATER_PASSED,
  559                     sizeof(struct ngm_queue_state), M_NOWAIT);
  560                 if (mesg == NULL)
  561                         break;
  562                 qstate = (struct ngm_queue_state *)mesg->data;
  563 
  564                 /* XXX have to figure out how to get that info */
  565 
  566                 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
  567                 break;
  568             }
  569 
  570           case ATMEV_VCC_CHANGED:
  571             {
  572                 struct atmev_vcc_changed *ev = arg;
  573                 struct ngm_atm_vcc_change *chg;
  574 
  575                 if (priv->manage == NULL)
  576                         break;
  577                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
  578                     sizeof(struct ngm_atm_vcc_change), M_NOWAIT);
  579                 if (mesg == NULL)
  580                         break;
  581                 chg = (struct ngm_atm_vcc_change *)mesg->data;
  582                 chg->vci = ev->vci;
  583                 chg->vpi = ev->vpi;
  584                 chg->state = (ev->up != 0);
  585                 chg->node = NG_NODE_ID(node);
  586                 NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
  587                 break;
  588             }
  589 
  590           case ATMEV_IFSTATE_CHANGED:
  591             {
  592                 struct atmev_ifstate_changed *ev = arg;
  593                 struct ngm_atm_if_change *chg;
  594 
  595                 if (priv->manage == NULL)
  596                         break;
  597                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_IF_CHANGE,
  598                     sizeof(struct ngm_atm_if_change), M_NOWAIT);
  599                 if (mesg == NULL)
  600                         break;
  601                 chg = (struct ngm_atm_if_change *)mesg->data;
  602                 chg->carrier = (ev->carrier != 0);
  603                 chg->running = (ev->running != 0);
  604                 chg->node = NG_NODE_ID(node);
  605                 NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
  606                 break;
  607             }
  608 
  609           case ATMEV_ACR_CHANGED:
  610             {
  611                 struct atmev_acr_changed *ev = arg;
  612                 struct ngm_atm_acr_change *acr;
  613 
  614                 /* find the connection */
  615                 LIST_FOREACH(vcc, &priv->vccs, link)
  616                         if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
  617                                 break;
  618                 if (vcc == NULL)
  619                         break;
  620 
  621                 /* convert into a flow control message */
  622                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_ACR_CHANGE,
  623                     sizeof(struct ngm_atm_acr_change), M_NOWAIT);
  624                 if (mesg == NULL)
  625                         break;
  626                 acr = (struct ngm_atm_acr_change *)mesg->data;
  627                 acr->node = NG_NODE_ID(node);
  628                 acr->vci = ev->vci;
  629                 acr->vpi = ev->vpi;
  630                 acr->acr = ev->acr;
  631 
  632                 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
  633                 break;
  634             }
  635         }
  636 }
  637 
  638 /*
  639  * Use send_fn to get the right lock
  640  */
  641 static void
  642 ng_atm_event(struct ifnet *ifp, uint32_t event, void *arg)
  643 {
  644         const node_p node = IFP2NG(ifp);
  645 
  646         if (node != NULL)
  647                 /* may happen during attach/detach */
  648                 (void)ng_send_fn(node, NULL, ng_atm_event_func, arg, event);
  649 }
  650 
  651 /************************************************************
  652  *
  653  * CPCS
  654  */
  655 /*
  656  * Open a channel for the user
  657  */
  658 static int
  659 ng_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
  660 {
  661         struct priv *priv = NG_NODE_PRIVATE(node);
  662         const struct ifatm_mib *mib;
  663         struct ngvcc *vcc;
  664         struct atmio_openvcc data;
  665         int err;
  666 
  667         if(priv->ifp->if_ioctl == NULL)
  668                 return (ENXIO);
  669 
  670         mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
  671 
  672         LIST_FOREACH(vcc, &priv->vccs, link)
  673                 if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
  674                         break;
  675         if (vcc == NULL)
  676                 return (ENOTCONN);
  677         if (vcc->flags & VCC_OPEN)
  678                 return (EISCONN);
  679 
  680         /*
  681          * Check user arguments and construct ioctl argument
  682          */
  683         memset(&data, 0, sizeof(data));
  684 
  685         data.rxhand = vcc;
  686 
  687         switch (data.param.aal = arg->aal) {
  688 
  689           case ATMIO_AAL_34:
  690           case ATMIO_AAL_5:
  691           case ATMIO_AAL_0:
  692           case ATMIO_AAL_RAW:
  693                 break;
  694 
  695           default:
  696                 return (EINVAL);
  697         }
  698 
  699         if (arg->vpi > 0xff)
  700                 return (EINVAL);
  701         data.param.vpi = arg->vpi;
  702 
  703         /* allow 0.0 as catch all receive channel */
  704         if (arg->vci == 0 && (arg->vpi != 0 || !(arg->flags & ATMIO_FLAG_NOTX)))
  705                 return (EINVAL);
  706         data.param.vci = arg->vci;
  707 
  708         data.param.tparam.pcr = arg->pcr;
  709 
  710         if (arg->mcr > arg->pcr)
  711                 return (EINVAL);
  712         data.param.tparam.mcr = arg->mcr;
  713 
  714         if (!(arg->flags & ATMIO_FLAG_NOTX)) {
  715                 if (arg->tmtu == 0)
  716                         data.param.tmtu = priv->ifp->if_mtu;
  717                 else {
  718                         data.param.tmtu = arg->tmtu;
  719                 }
  720         }
  721         if (!(arg->flags & ATMIO_FLAG_NORX)) {
  722                 if (arg->rmtu == 0)
  723                         data.param.rmtu = priv->ifp->if_mtu;
  724                 else {
  725                         data.param.rmtu = arg->rmtu;
  726                 }
  727         }
  728 
  729         switch (data.param.traffic = arg->traffic) {
  730 
  731           case ATMIO_TRAFFIC_UBR:
  732           case ATMIO_TRAFFIC_CBR:
  733                 break;
  734 
  735           case ATMIO_TRAFFIC_VBR:
  736                 if (arg->scr > arg->pcr)
  737                         return (EINVAL);
  738                 data.param.tparam.scr = arg->scr;
  739 
  740                 if (arg->mbs > (1 << 24))
  741                         return (EINVAL);
  742                 data.param.tparam.mbs = arg->mbs;
  743                 break;
  744 
  745           case ATMIO_TRAFFIC_ABR:
  746                 if (arg->icr > arg->pcr || arg->icr < arg->mcr)
  747                         return (EINVAL);
  748                 data.param.tparam.icr = arg->icr;
  749 
  750                 if (arg->tbe == 0 || arg->tbe > (1 << 24))
  751                         return (EINVAL);
  752                 data.param.tparam.tbe = arg->tbe;
  753 
  754                 if (arg->nrm > 0x7)
  755                         return (EINVAL);
  756                 data.param.tparam.nrm = arg->nrm;
  757 
  758                 if (arg->trm > 0x7)
  759                         return (EINVAL);
  760                 data.param.tparam.trm = arg->trm;
  761 
  762                 if (arg->adtf > 0x3ff)
  763                         return (EINVAL);
  764                 data.param.tparam.adtf = arg->adtf;
  765 
  766                 if (arg->rif > 0xf)
  767                         return (EINVAL);
  768                 data.param.tparam.rif = arg->rif;
  769 
  770                 if (arg->rdf > 0xf)
  771                         return (EINVAL);
  772                 data.param.tparam.rdf = arg->rdf;
  773 
  774                 if (arg->cdf > 0x7)
  775                         return (EINVAL);
  776                 data.param.tparam.cdf = arg->cdf;
  777 
  778                 break;
  779 
  780           default:
  781                 return (EINVAL);
  782         }
  783 
  784         if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
  785                 return (EINVAL);
  786 
  787         data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
  788         data.param.flags |= ATMIO_FLAG_NG;
  789 
  790         err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
  791 
  792         if (err == 0) {
  793                 vcc->vci = data.param.vci;
  794                 vcc->vpi = data.param.vpi;
  795                 vcc->flags = VCC_OPEN;
  796         }
  797 
  798         return (err);
  799 }
  800 
  801 /*
  802  * Issue the close command to the driver
  803  */
  804 static int
  805 cpcs_term(const struct priv *priv, u_int vpi, u_int vci)
  806 {
  807         struct atmio_closevcc data;
  808 
  809         if (priv->ifp->if_ioctl == NULL)
  810                 return ENXIO;
  811 
  812         data.vpi = vpi;
  813         data.vci = vci;
  814 
  815         return ((*priv->ifp->if_ioctl)(priv->ifp,
  816             SIOCATMCLOSEVCC, (caddr_t)&data));
  817 }
  818 
  819 
  820 /*
  821  * Close a channel by request of the user
  822  */
  823 static int
  824 ng_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
  825 {
  826         struct priv *priv = NG_NODE_PRIVATE(node);
  827         struct ngvcc *vcc;
  828         int error;
  829 
  830         LIST_FOREACH(vcc, &priv->vccs, link)
  831                 if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
  832                         break;
  833         if (vcc == NULL)
  834                 return (ENOTCONN);
  835         if (!(vcc->flags & VCC_OPEN))
  836                 return (ENOTCONN);
  837 
  838         error = cpcs_term(priv, vcc->vpi, vcc->vci);
  839 
  840         vcc->vci = 0;
  841         vcc->vpi = 0;
  842         vcc->flags = 0;
  843 
  844         return (error);
  845 }
  846 
  847 /************************************************************/
  848 /*
  849  * CONTROL MESSAGES
  850  */
  851 
  852 /*
  853  * Produce a textual description of the current status
  854  */
  855 static int
  856 text_status(node_p node, char *arg, u_int len)
  857 {
  858         const struct priv *priv = NG_NODE_PRIVATE(node);
  859         const struct ifatm_mib *mib;
  860         struct sbuf sbuf;
  861         u_int i;
  862 
  863         static const struct {
  864                 const char      *name;
  865                 const char      *vendor;
  866         } devices[] = {
  867                 ATM_DEVICE_NAMES
  868         };
  869 
  870         mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
  871 
  872         sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
  873         sbuf_printf(&sbuf, "interface: %s\n", priv->ifp->if_xname);
  874 
  875         if (mib->device >= nitems(devices))
  876                 sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
  877         else
  878                 sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
  879                     devices[mib->device].name, devices[mib->device].vendor);
  880 
  881         for (i = 0; atmmedia[i].name; i++)
  882                 if(mib->media == atmmedia[i].media) {
  883                         sbuf_printf(&sbuf, "media=%s\n", atmmedia[i].name);
  884                         break;
  885                 }
  886         if(atmmedia[i].name == NULL)
  887                 sbuf_printf(&sbuf, "media=unknown\n");
  888 
  889         sbuf_printf(&sbuf, "serial=%u esi=%6D hardware=%u software=%u\n",
  890             mib->serial, mib->esi, ":", mib->hw_version, mib->sw_version);
  891         sbuf_printf(&sbuf, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
  892             "max_vccs=%u\n", mib->pcr, mib->vpi_bits, mib->vci_bits,
  893             mib->max_vpcs, mib->max_vccs);
  894         sbuf_printf(&sbuf, "ifflags=%b\n", priv->ifp->if_flags, IFFLAGS);
  895 
  896         sbuf_finish(&sbuf);
  897 
  898         return (sbuf_len(&sbuf));
  899 }
  900 
  901 /*
  902  * Get control message
  903  */
  904 static int
  905 ng_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
  906 {
  907         const struct priv *priv = NG_NODE_PRIVATE(node);
  908         struct ng_mesg *resp = NULL;
  909         struct ng_mesg *msg;
  910         struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
  911         int error = 0;
  912 
  913         NGI_GET_MSG(item, msg);
  914 
  915         switch (msg->header.typecookie) {
  916 
  917           case NGM_GENERIC_COOKIE:
  918                 switch (msg->header.cmd) {
  919 
  920                   case NGM_TEXT_STATUS:
  921                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
  922                         if(resp == NULL) {
  923                                 error = ENOMEM;
  924                                 break;
  925                         }
  926 
  927                         resp->header.arglen = text_status(node,
  928                             (char *)resp->data, resp->header.arglen) + 1;
  929                         break;
  930 
  931                   default:
  932                         error = EINVAL;
  933                         break;
  934                 }
  935                 break;
  936 
  937           case NGM_ATM_COOKIE:
  938                 switch (msg->header.cmd) {
  939 
  940                   case NGM_ATM_GET_IFNAME:
  941                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
  942                         if (resp == NULL) {
  943                                 error = ENOMEM;
  944                                 break;
  945                         }
  946                         strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
  947                         break;
  948 
  949                   case NGM_ATM_GET_CONFIG:
  950                     {
  951                         struct ngm_atm_config *config;
  952 
  953                         NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
  954                         if (resp == NULL) {
  955                                 error = ENOMEM;
  956                                 break;
  957                         }
  958                         config = (struct ngm_atm_config *)resp->data;
  959                         config->pcr = mib->pcr;
  960                         config->vpi_bits = mib->vpi_bits;
  961                         config->vci_bits = mib->vci_bits;
  962                         config->max_vpcs = mib->max_vpcs;
  963                         config->max_vccs = mib->max_vccs;
  964                         break;
  965                     }
  966 
  967                   case NGM_ATM_GET_VCCS:
  968                     {
  969                         struct atmio_vcctable *vccs;
  970                         size_t len;
  971 
  972                         if (priv->ifp->if_ioctl == NULL) {
  973                                 error = ENXIO;
  974                                 break;
  975                         }
  976                         error = (*priv->ifp->if_ioctl)(priv->ifp,
  977                             SIOCATMGETVCCS, (caddr_t)&vccs);
  978                         if (error)
  979                                 break;
  980 
  981                         len = sizeof(*vccs) +
  982                             vccs->count * sizeof(vccs->vccs[0]);
  983                         NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
  984                         if (resp == NULL) {
  985                                 error = ENOMEM;
  986                                 free(vccs, M_DEVBUF);
  987                                 break;
  988                         }
  989 
  990                         (void)memcpy(resp->data, vccs, len);
  991                         free(vccs, M_DEVBUF);
  992 
  993                         break;
  994                     }
  995 
  996                   case NGM_ATM_GET_VCC:
  997                     {
  998                         char hook[NG_HOOKSIZ];
  999                         struct atmio_vcctable *vccs;
 1000                         struct ngvcc *vcc;
 1001                         u_int i;
 1002 
 1003                         if (priv->ifp->if_ioctl == NULL) {
 1004                                 error = ENXIO;
 1005                                 break;
 1006                         }
 1007                         if (msg->header.arglen != NG_HOOKSIZ) {
 1008                                 error = EINVAL;
 1009                                 break;
 1010                         }
 1011                         strncpy(hook, msg->data, NG_HOOKSIZ);
 1012                         hook[NG_HOOKSIZ - 1] = '\0';
 1013                         LIST_FOREACH(vcc, &priv->vccs, link)
 1014                                 if (strcmp(NG_HOOK_NAME(vcc->hook), hook) == 0)
 1015                                         break;
 1016                         if (vcc == NULL) {
 1017                                 error = ENOTCONN;
 1018                                 break;
 1019                         }
 1020                         error = (*priv->ifp->if_ioctl)(priv->ifp,
 1021                             SIOCATMGETVCCS, (caddr_t)&vccs);
 1022                         if (error)
 1023                                 break;
 1024 
 1025                         for (i = 0; i < vccs->count; i++)
 1026                                 if (vccs->vccs[i].vpi == vcc->vpi &&
 1027                                     vccs->vccs[i].vci == vcc->vci)
 1028                                         break;
 1029                         if (i == vccs->count) {
 1030                                 error = ENOTCONN;
 1031                                 free(vccs, M_DEVBUF);
 1032                                 break;
 1033                         }
 1034 
 1035                         NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
 1036                             M_NOWAIT);
 1037                         if (resp == NULL) {
 1038                                 error = ENOMEM;
 1039                                 free(vccs, M_DEVBUF);
 1040                                 break;
 1041                         }
 1042 
 1043                         *(struct atmio_vcc *)resp->data = vccs->vccs[i];
 1044                         free(vccs, M_DEVBUF);
 1045                         break;
 1046                     }
 1047 
 1048                   case NGM_ATM_GET_VCCID:
 1049                     {
 1050                         struct atmio_vcc *arg;
 1051                         struct atmio_vcctable *vccs;
 1052                         u_int i;
 1053 
 1054                         if (priv->ifp->if_ioctl == NULL) {
 1055                                 error = ENXIO;
 1056                                 break;
 1057                         }
 1058                         if (msg->header.arglen != sizeof(*arg)) {
 1059                                 error = EINVAL;
 1060                                 break;
 1061                         }
 1062                         arg = (struct atmio_vcc *)msg->data;
 1063 
 1064                         error = (*priv->ifp->if_ioctl)(priv->ifp,
 1065                             SIOCATMGETVCCS, (caddr_t)&vccs);
 1066                         if (error)
 1067                                 break;
 1068 
 1069                         for (i = 0; i < vccs->count; i++)
 1070                                 if (vccs->vccs[i].vpi == arg->vpi &&
 1071                                     vccs->vccs[i].vci == arg->vci)
 1072                                         break;
 1073                         if (i == vccs->count) {
 1074                                 error = ENOTCONN;
 1075                                 free(vccs, M_DEVBUF);
 1076                                 break;
 1077                         }
 1078 
 1079                         NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
 1080                             M_NOWAIT);
 1081                         if (resp == NULL) {
 1082                                 error = ENOMEM;
 1083                                 free(vccs, M_DEVBUF);
 1084                                 break;
 1085                         }
 1086 
 1087                         *(struct atmio_vcc *)resp->data = vccs->vccs[i];
 1088                         free(vccs, M_DEVBUF);
 1089                         break;
 1090                     }
 1091 
 1092                   case NGM_ATM_CPCS_INIT:
 1093                         if (msg->header.arglen !=
 1094                             sizeof(struct ngm_atm_cpcs_init)) {
 1095                                 error = EINVAL;
 1096                                 break;
 1097                         }
 1098                         error = ng_atm_cpcs_init(node,
 1099                             (struct ngm_atm_cpcs_init *)msg->data);
 1100                         break;
 1101 
 1102                   case NGM_ATM_CPCS_TERM:
 1103                         if (msg->header.arglen !=
 1104                             sizeof(struct ngm_atm_cpcs_term)) {
 1105                                 error = EINVAL;
 1106                                 break;
 1107                         }
 1108                         error = ng_atm_cpcs_term(node,
 1109                             (struct ngm_atm_cpcs_term *)msg->data);
 1110                         break;
 1111 
 1112                   case NGM_ATM_GET_STATS:
 1113                     {
 1114                         struct ngm_atm_stats *p;
 1115 
 1116                         if (msg->header.arglen != 0) {
 1117                                 error = EINVAL;
 1118                                 break;
 1119                         }
 1120                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
 1121                         if (resp == NULL) {
 1122                                 error = ENOMEM;
 1123                                 break;
 1124                         }
 1125                         p = (struct ngm_atm_stats *)resp->data;
 1126                         p->in_packets = priv->in_packets;
 1127                         p->out_packets = priv->out_packets;
 1128                         p->in_errors = priv->in_errors;
 1129                         p->out_errors = priv->out_errors;
 1130 
 1131                         break;
 1132                     }
 1133 
 1134                   default:
 1135                         error = EINVAL;
 1136                         break;
 1137                 }
 1138                 break;
 1139 
 1140           default:
 1141                 error = EINVAL;
 1142                 break;
 1143         }
 1144 
 1145         NG_RESPOND_MSG(error, node, item, resp);
 1146         NG_FREE_MSG(msg);
 1147         return (error);
 1148 }
 1149 
 1150 /************************************************************/
 1151 /*
 1152  * HOOK MANAGEMENT
 1153  */
 1154 
 1155 /*
 1156  * A new hook is create that will be connected to the node.
 1157  * Check, whether the name is one of the predefined ones.
 1158  * If not, create a new entry into the vcc list.
 1159  */
 1160 static int
 1161 ng_atm_newhook(node_p node, hook_p hook, const char *name)
 1162 {
 1163         struct priv *priv = NG_NODE_PRIVATE(node);
 1164         struct ngvcc *vcc;
 1165 
 1166         if (strcmp(name, "input") == 0) {
 1167                 priv->input = hook;
 1168                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
 1169                 return (0);
 1170         }
 1171         if (strcmp(name, "output") == 0) {
 1172                 priv->output = hook;
 1173                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
 1174                 return (0);
 1175         }
 1176         if (strcmp(name, "orphans") == 0) {
 1177                 priv->orphans = hook;
 1178                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
 1179                 return (0);
 1180         }
 1181 
 1182         /*
 1183          * Allocate a new entry
 1184          */
 1185         vcc = malloc(sizeof(*vcc), M_NETGRAPH, M_NOWAIT | M_ZERO);
 1186         if (vcc == NULL)
 1187                 return (ENOMEM);
 1188 
 1189         vcc->hook = hook;
 1190         NG_HOOK_SET_PRIVATE(hook, vcc);
 1191 
 1192         LIST_INSERT_HEAD(&priv->vccs, vcc, link);
 1193 
 1194         if (strcmp(name, "manage") == 0)
 1195                 priv->manage = hook;
 1196 
 1197         return (0);
 1198 }
 1199 
 1200 /*
 1201  * Connect. Set the peer to queuing.
 1202  */
 1203 static int
 1204 ng_atm_connect(hook_p hook)
 1205 {
 1206         if (NG_HOOK_PRIVATE(hook) != NULL)
 1207                 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
 1208 
 1209         return (0);
 1210 }
 1211 
 1212 /*
 1213  * Disconnect a HOOK
 1214  */
 1215 static int
 1216 ng_atm_disconnect(hook_p hook)
 1217 {
 1218         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
 1219         struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
 1220 
 1221         if (vcc == NULL) {
 1222                 if (hook == priv->output) {
 1223                         priv->output = NULL;
 1224                         return (0);
 1225                 }
 1226                 if (hook == priv->input) {
 1227                         priv->input = NULL;
 1228                         return (0);
 1229                 }
 1230                 if (hook == priv->orphans) {
 1231                         priv->orphans = NULL;
 1232                         return (0);
 1233                 }
 1234                 log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
 1235                 return (0);
 1236         }
 1237 
 1238         /* don't terminate if we are detaching from the interface */
 1239         if ((vcc->flags & VCC_OPEN) && priv->ifp != NULL)
 1240                 (void)cpcs_term(priv, vcc->vpi, vcc->vci);
 1241 
 1242         NG_HOOK_SET_PRIVATE(hook, NULL);
 1243 
 1244         LIST_REMOVE(vcc, link);
 1245         free(vcc, M_NETGRAPH);
 1246 
 1247         if (hook == priv->manage)
 1248                 priv->manage = NULL;
 1249 
 1250         return (0);
 1251 }
 1252 
 1253 /************************************************************/
 1254 /*
 1255  * NODE MANAGEMENT
 1256  */
 1257 
 1258 /*
 1259  * ATM interface attached - create a node and name it like the interface.
 1260  */
 1261 static void
 1262 ng_atm_attach(struct ifnet *ifp)
 1263 {
 1264         node_p node;
 1265         struct priv *priv;
 1266 
 1267         KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __func__));
 1268 
 1269         if (ng_make_node_common(&ng_atm_typestruct, &node) != 0) {
 1270                 log(LOG_ERR, "%s: can't create node for %s\n",
 1271                     __func__, ifp->if_xname);
 1272                 return;
 1273         }
 1274 
 1275         priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
 1276         if (priv == NULL) {
 1277                 log(LOG_ERR, "%s: can't allocate memory for %s\n",
 1278                     __func__, ifp->if_xname);
 1279                 NG_NODE_UNREF(node);
 1280                 return;
 1281         }
 1282         NG_NODE_SET_PRIVATE(node, priv);
 1283         priv->ifp = ifp;
 1284         LIST_INIT(&priv->vccs);
 1285         IFP2NG_SET(ifp, node);
 1286 
 1287         if (ng_name_node(node, ifp->if_xname) != 0) {
 1288                 log(LOG_WARNING, "%s: can't name node %s\n",
 1289                     __func__, ifp->if_xname);
 1290         }
 1291 }
 1292 
 1293 /*
 1294  * ATM interface detached - destroy node.
 1295  */
 1296 static void
 1297 ng_atm_detach(struct ifnet *ifp)
 1298 {
 1299         const node_p node = IFP2NG(ifp);
 1300         struct priv *priv;
 1301 
 1302         if(node == NULL)
 1303                 return;
 1304 
 1305         NG_NODE_REALLY_DIE(node);
 1306 
 1307         priv = NG_NODE_PRIVATE(node);
 1308         IFP2NG_SET(priv->ifp, NULL);
 1309         priv->ifp = NULL;
 1310 
 1311         ng_rmnode_self(node);
 1312 }
 1313 
 1314 /*
 1315  * Shutdown the node. This is called from the shutdown message processing.
 1316  */
 1317 static int
 1318 ng_atm_shutdown(node_p node)
 1319 {
 1320         struct priv *priv = NG_NODE_PRIVATE(node);
 1321 
 1322         if (node->nd_flags & NGF_REALLY_DIE) {
 1323                 /*
 1324                  * We are called from unloading the ATM driver. Really,
 1325                  * really need to shutdown this node. The ifp was
 1326                  * already handled in the detach routine.
 1327                  */
 1328                 NG_NODE_SET_PRIVATE(node, NULL);
 1329                 free(priv, M_NETGRAPH);
 1330 
 1331                 NG_NODE_UNREF(node);
 1332                 return (0);
 1333         }
 1334 
 1335 #ifdef NGATM_DEBUG
 1336         if (!allow_shutdown)
 1337                 NG_NODE_REVIVE(node);           /* we persist */
 1338         else {
 1339                 IFP2NG_SET(priv->ifp, NULL);
 1340                 NG_NODE_SET_PRIVATE(node, NULL);
 1341                 free(priv, M_NETGRAPH);
 1342                 NG_NODE_UNREF(node);
 1343         }
 1344 #else
 1345         /*
 1346          * We are persistent - reinitialize.
 1347          */
 1348         NG_NODE_REVIVE(node);
 1349 #endif
 1350         return (0);
 1351 }
 1352 
 1353 /*
 1354  * Nodes are constructed only via interface attaches.
 1355  */
 1356 static int
 1357 ng_atm_constructor(node_p nodep)
 1358 {
 1359         return (EINVAL);
 1360 }
 1361 
 1362 /************************************************************/
 1363 /*
 1364  * INITIALISATION
 1365  */
 1366 /*
 1367  * Loading and unloading of node type
 1368  *
 1369  * The assignments to the globals for the hooks should be ok without
 1370  * a special hook. The use pattern is generally: check that the pointer
 1371  * is not NULL, call the function. In the attach case this is no problem.
 1372  * In the detach case we can detach only when no ATM node exists. That
 1373  * means that there is no ATM interface anymore. So we are sure that
 1374  * we are not in the code path in if_atmsubr.c. To prevent someone
 1375  * from adding an interface after we have started to unload the node, we
 1376  * take the iflist lock so an if_attach will be blocked until we are done.
 1377  * XXX: perhaps the function pointers should be 'volatile' for this to work
 1378  * properly.
 1379  */
 1380 static int
 1381 ng_atm_mod_event(module_t mod, int event, void *data)
 1382 {
 1383         VNET_ITERATOR_DECL(vnet_iter);
 1384         struct ifnet *ifp;
 1385         int error = 0;
 1386 
 1387         switch (event) {
 1388 
 1389           case MOD_LOAD:
 1390                 /*
 1391                  * Register function hooks
 1392                  */
 1393                 if (ng_atm_attach_p != NULL) {
 1394                         error = EEXIST;
 1395                         break;
 1396                 }
 1397                 IFNET_RLOCK();
 1398 
 1399                 ng_atm_attach_p = ng_atm_attach;
 1400                 ng_atm_detach_p = ng_atm_detach;
 1401                 ng_atm_output_p = ng_atm_output;
 1402                 ng_atm_input_p = ng_atm_input;
 1403                 ng_atm_input_orphan_p = ng_atm_input_orphans;
 1404                 ng_atm_event_p = ng_atm_event;
 1405 
 1406                 /* Create nodes for existing ATM interfaces */
 1407                 VNET_LIST_RLOCK();
 1408                 VNET_FOREACH(vnet_iter) {
 1409                         CURVNET_SET_QUIET(vnet_iter);
 1410                         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 1411                                 if (ifp->if_type == IFT_ATM)
 1412                                         ng_atm_attach(ifp);
 1413                         }
 1414                         CURVNET_RESTORE();
 1415                 }
 1416                 VNET_LIST_RUNLOCK();
 1417                 IFNET_RUNLOCK();
 1418                 break;
 1419 
 1420           case MOD_UNLOAD:
 1421                 IFNET_RLOCK();
 1422 
 1423                 ng_atm_attach_p = NULL;
 1424                 ng_atm_detach_p = NULL;
 1425                 ng_atm_output_p = NULL;
 1426                 ng_atm_input_p = NULL;
 1427                 ng_atm_input_orphan_p = NULL;
 1428                 ng_atm_event_p = NULL;
 1429 
 1430                 VNET_LIST_RLOCK();
 1431                 VNET_FOREACH(vnet_iter) {
 1432                         CURVNET_SET_QUIET(vnet_iter);
 1433                         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 1434                                 if (ifp->if_type == IFT_ATM)
 1435                                         ng_atm_detach(ifp);
 1436                         }
 1437                         CURVNET_RESTORE();
 1438                 }
 1439                 VNET_LIST_RUNLOCK();
 1440                 IFNET_RUNLOCK();
 1441                 break;
 1442 
 1443           default:
 1444                 error = EOPNOTSUPP;
 1445                 break;
 1446         }
 1447         return (error);
 1448 }

Cache object: 438e5e4feeac7eb60b434b513c2484c8


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