The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/atm/ng_atm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: df566d8ee4594577e038bd0adc891091


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