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

Cache object: 85a1254bc5ab65ab26598ed4cd79da76


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