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

Cache object: 1bd14bc731ad61ad1dc12c509fca341e


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