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/netatm/atm_cm.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *
    3  * ===================================
    4  * HARP  |  Host ATM Research Platform
    5  * ===================================
    6  *
    7  *
    8  * This Host ATM Research Platform ("HARP") file (the "Software") is
    9  * made available by Network Computing Services, Inc. ("NetworkCS")
   10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
   11  * support of any kind.
   12  *
   13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   17  * In no event shall NetworkCS be responsible for any damages, including
   18  * but not limited to consequential damages, arising from or relating to
   19  * any use of the Software or related support.
   20  *
   21  * Copyright 1994-1998 Network Computing Services, Inc.
   22  *
   23  * Copies of this Software may be made, however, the above copyright
   24  * notice must be reproduced on all copies.
   25  *
   26  *      @(#) $FreeBSD: src/sys/netatm/atm_cm.c,v 1.25 2003/02/19 05:47:30 imp Exp $
   27  *
   28  */
   29 
   30 /*
   31  * Core ATM Services
   32  * -----------------
   33  *
   34  * ATM Connection Manager
   35  *
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/errno.h>
   41 #include <sys/time.h>
   42 #include <sys/socket.h>
   43 #include <sys/socketvar.h>
   44 #include <sys/syslog.h>
   45 #include <net/if.h>
   46 #include <netatm/port.h>
   47 #include <netatm/queue.h>
   48 #include <netatm/atm.h>
   49 #include <netatm/atm_sys.h>
   50 #include <netatm/atm_sap.h>
   51 #include <netatm/atm_cm.h>
   52 #include <netatm/atm_if.h>
   53 #include <netatm/atm_vc.h>
   54 #include <netatm/atm_sigmgr.h>
   55 #include <netatm/atm_stack.h>
   56 #include <netatm/atm_pcb.h>
   57 #include <netatm/atm_var.h>
   58 
   59 #ifndef lint
   60 __RCSID("@(#) $FreeBSD: src/sys/netatm/atm_cm.c,v 1.25 2003/02/19 05:47:30 imp Exp $");
   61 #endif
   62 
   63 
   64 /*
   65  * Global variables
   66  */
   67 struct atm_cm_stat      atm_cm_stat = {0};
   68 
   69 /*
   70  * Local functions
   71  */
   72 static void             atm_cm_cpcs_upper(int, void *, intptr_t, intptr_t);
   73 static void             atm_cm_saal_upper(int, void *, intptr_t, intptr_t);
   74 static void             atm_cm_sscop_upper(int, void *, intptr_t, intptr_t);
   75 static Atm_connvc *     atm_cm_share_llc(Atm_attributes *);
   76 static void             atm_cm_closeconn(Atm_connection *,
   77                                 struct t_atm_cause *);
   78 static void             atm_cm_closevc(Atm_connvc *);
   79 static void             atm_cm_timeout(struct atm_time *);
   80 static KTimeout_ret     atm_cm_procinq(void *);
   81 static void             atm_cm_incall(Atm_connvc *);
   82 static int              atm_cm_accept(Atm_connvc *, Atm_connection *);
   83 
   84 /*
   85  * Local variables
   86  */
   87 static Queue_t          atm_connection_queue = {NULL};
   88 static Queue_t          atm_incoming_queue = {NULL};
   89 static int              atm_incoming_qlen = 0;
   90 static Atm_connection   *atm_listen_queue = NULL;
   91 static struct attr_cause        atm_cause_tmpl = 
   92         {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
   93 
   94 /*
   95  * Stack commands, indexed by API
   96  */
   97 static struct {
   98         int             init;
   99         int             term;
  100 } atm_stackcmds[] = {
  101         {CPCS_INIT, CPCS_TERM},         /* CMAPI_CPCS */
  102         {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
  103         {SSCOP_INIT, SSCOP_TERM},       /* CMAPI_SSCOP */
  104 };
  105 
  106 static uma_zone_t atm_connection_zone;
  107 static uma_zone_t atm_connvc_zone;
  108 
  109 void
  110 atm_cm_init(void)
  111 {
  112 
  113         atm_connection_zone = uma_zcreate("atm connection",
  114             sizeof(Atm_connection), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  115         uma_zone_set_max(atm_connection_zone, 100);
  116 
  117         atm_connvc_zone = uma_zcreate("atm connvc", sizeof(Atm_connvc), NULL,
  118             NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  119         uma_zone_set_max(atm_connvc_zone, 100);
  120 }
  121 
  122 /*
  123  * Initiate Outgoing ATM Call
  124  * 
  125  * Called by an endpoint service to create a new Connection Manager API
  126  * instance and to initiate an outbound ATM connection.  The endpoint
  127  * provided token will be used in all further CM -> endpoint function
  128  * calls, and the returned connection block pointer must be used in all
  129  * subsequent endpoint -> CM function calls.
  130  *
  131  * If the return indicates that the connection setup has been immediately
  132  * successful (typically only for PVCs and shared SVCs), then the connection
  133  * is ready for data transmission.
  134  *
  135  * If the return indicates that the connection setup is still in progress,
  136  * then the endpoint must wait for notification from the Connection Manager
  137  * indicating the final status of the call setup.  If the call setup completes
  138  * successfully, then a "call connected" notification will be sent to the
  139  * endpoint by the Connection Manager.  If the call setup fails, then the
  140  * endpoint will receive a "call cleared" notification.
  141  *
  142  * All connection instances must be freed with an atm_cm_release() call.
  143  *
  144  * Arguments:
  145  *      epp     pointer to endpoint definition structure
  146  *      token   endpoint's connection instance token
  147  *      ap      pointer to requested connection attributes
  148  *      copp    pointer to location to return allocated connection block
  149  *
  150  * Returns:
  151  *      0       connection has been successfully established
  152  *      EINPROGRESS     connection establishment is in progress
  153  *      errno   connection failed - reason indicated
  154  *
  155  */
  156 int
  157 atm_cm_connect(epp, token, ap, copp)
  158         Atm_endpoint    *epp;
  159         void            *token;
  160         Atm_attributes  *ap;
  161         Atm_connection  **copp;
  162 {
  163         Atm_connection  *cop;
  164         Atm_connvc      *cvp;
  165         struct atm_pif  *pip;
  166         struct sigmgr   *smp;
  167         struct stack_list       sl;
  168         void            (*upf)(int, void *, intptr_t, intptr_t);
  169         int             s, sli, err, err2;
  170 
  171         *copp = NULL;
  172         cvp = NULL;
  173 
  174         /*
  175          * Get a connection block
  176          */
  177         cop = uma_zalloc(atm_connection_zone, M_WAITOK);
  178         if (cop == NULL)
  179                 return (ENOMEM);
  180 
  181         /*
  182          * Initialize connection info
  183          */
  184         cop->co_endpt = epp;
  185         cop->co_toku = token;
  186 
  187         /*
  188          * Initialize stack list index
  189          */
  190         sli = 0;
  191 
  192         /*
  193          * Validate and extract useful attribute information
  194          */
  195 
  196         /*
  197          * Must specify a network interface (validated below)
  198          */
  199         if (ap->nif == NULL) {
  200                 err = EINVAL;
  201                 goto done;
  202         }
  203 
  204         /*
  205          * Check out Data API
  206          */
  207         switch (ap->api) {
  208 
  209         case CMAPI_CPCS:
  210                 upf = atm_cm_cpcs_upper;
  211                 break;
  212 
  213         case CMAPI_SAAL:
  214                 sl.sl_sap[sli++] = SAP_SSCF_UNI;
  215                 sl.sl_sap[sli++] = SAP_SSCOP;
  216                 upf = atm_cm_saal_upper;
  217                 break;
  218 
  219         case CMAPI_SSCOP:
  220                 sl.sl_sap[sli++] = SAP_SSCOP;
  221                 upf = atm_cm_sscop_upper;
  222                 break;
  223 
  224         default:
  225                 err = EINVAL;
  226                 goto done;
  227         }
  228 
  229         /*
  230          * AAL Attributes
  231          */
  232         if (ap->aal.tag != T_ATM_PRESENT) {
  233                 err = EINVAL;
  234                 goto done;
  235         }
  236 
  237         switch (ap->aal.type) {
  238 
  239         case ATM_AAL5:
  240                 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
  241                 sl.sl_sap[sli++] = SAP_SAR_AAL5;
  242                 sl.sl_sap[sli++] = SAP_ATM;
  243                 break;
  244 
  245         case ATM_AAL3_4:
  246                 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
  247                 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
  248                 sl.sl_sap[sli++] = SAP_ATM;
  249                 break;
  250 
  251         default:
  252                 err = EINVAL;
  253                 goto done;
  254         }
  255 
  256         /*
  257          * Broadband Bearer Attributes
  258          */
  259         if (ap->bearer.tag != T_ATM_PRESENT) {
  260                 err = EINVAL;
  261                 goto done;
  262         }
  263 
  264         switch (ap->bearer.v.connection_configuration) {
  265 
  266         case T_ATM_1_TO_1:
  267                 cop->co_flags |= COF_P2P;
  268                 break;
  269 
  270         case T_ATM_1_TO_MANY:
  271                 /* Not supported */
  272                 cop->co_flags |= COF_P2MP;
  273                 err = EINVAL;
  274                 goto done;
  275 
  276         default:
  277                 err = EINVAL;
  278                 goto done;
  279         }
  280 
  281         /*
  282          * Logical Link Control Attributes
  283          */
  284         if (ap->llc.tag == T_ATM_PRESENT) {
  285                 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
  286                     (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
  287                     (ap->blli.v.layer_2_protocol.ID.simple_ID != 
  288                                 T_ATM_BLLI2_I8802) ||
  289                     (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
  290                     (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
  291                         err = EINVAL;
  292                         goto done;
  293                 }
  294                 cop->co_mpx = ATM_ENC_LLC;
  295                 cop->co_llc = ap->llc;
  296         } else
  297                 cop->co_mpx = ATM_ENC_NULL;
  298 
  299         /*
  300          * Called Party Attributes
  301          */
  302         if (ap->called.tag != T_ATM_PRESENT) {
  303                 err = EINVAL;
  304                 goto done;
  305         }
  306 
  307         if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
  308             (ap->called.addr.address_length == 0)) {
  309                 err = EINVAL;
  310                 goto done;
  311         }
  312 
  313         /*
  314          * Calling Party Attributes
  315          */
  316         if (ap->calling.tag != T_ATM_ABSENT) {
  317                 err = EINVAL;
  318                 goto done;
  319         }
  320 
  321         /*
  322          * Quality of Service Attributes
  323          */
  324         if (ap->qos.tag != T_ATM_PRESENT) {
  325                 err = EINVAL;
  326                 goto done;
  327         }
  328 
  329         /*
  330          * Terminate stack list 
  331          */
  332         sl.sl_sap[sli] = 0;
  333 
  334         s = splnet();
  335 
  336         /*
  337          * Let multiplexors decide whether we need a new VCC
  338          */
  339         switch (cop->co_mpx) {
  340 
  341         case ATM_ENC_NULL:
  342                 /*
  343                  * All of these connections require a new VCC
  344                  */
  345                 break;
  346 
  347         case ATM_ENC_LLC:
  348                 /*
  349                  * See if we can share an existing LLC connection
  350                  */
  351                 cvp = atm_cm_share_llc(ap);
  352                 if (cvp == NULL)
  353                         break;
  354 
  355                 /*
  356                  * We've got a connection to share
  357                  */
  358                 cop->co_connvc = cvp;
  359                 if (cvp->cvc_state == CVCS_ACTIVE) {
  360                         cop->co_state = COS_ACTIVE;
  361                         err = 0;
  362                 } else {
  363                         cop->co_state = COS_OUTCONN;
  364                         err = EINPROGRESS;
  365                 }
  366                 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
  367                 cop->co_mxh = cvp->cvc_conn->co_mxh;
  368                 *copp = cop;
  369 
  370                 (void) splx(s);
  371                 return (err);
  372 
  373         default:
  374                 panic("atm_cm_connect: unknown mpx");
  375         }
  376 
  377         /*
  378          * If we get here, it means we need to create 
  379          * a new VCC for this connection
  380          */
  381 
  382         /*
  383          * Validate that network interface is registered and that 
  384          * a signalling manager is attached
  385          */
  386         for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
  387                 struct atm_nif  *nip;
  388                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
  389                         if (nip == ap->nif)
  390                                 break;
  391                 }
  392                 if (nip)
  393                         break;
  394         }
  395         if (pip == NULL) {
  396                 err = ENXIO;
  397                 goto donex;
  398         }
  399 
  400         if ((smp = pip->pif_sigmgr) == NULL) {
  401                 err = ENXIO;
  402                 goto donex;
  403         }
  404 
  405         /*
  406          * Get a connection VCC block
  407          */
  408         cvp = uma_zalloc(atm_connvc_zone, M_WAITOK);
  409         if (cvp == NULL) {
  410                 err = ENOMEM;
  411                 goto donex;
  412         }
  413 
  414         /*
  415          * Save VCC attributes
  416          */
  417         cvp->cvc_attr = *ap;
  418         cvp->cvc_flags |= CVCF_CALLER;
  419 
  420         /*
  421          * Link the control blocks
  422          */
  423         cop->co_connvc = cvp;
  424         cvp->cvc_conn = cop;
  425         cvp->cvc_sigmgr = smp;
  426 
  427         /*
  428          * Create a service stack
  429          */
  430         err = atm_create_stack(cvp, &sl, upf);
  431         if (err) {
  432                 cvp->cvc_state = CVCS_CLEAR;
  433                 atm_cm_closevc(cvp);
  434                 goto donex;
  435         }
  436 
  437         /*
  438          * Let the signalling manager handle the VCC creation
  439          */
  440         cvp->cvc_state = CVCS_SETUP;
  441         switch ((*smp->sm_setup)(cvp, &err)) {
  442 
  443         case CALL_CONNECTED:
  444                 /*
  445                  * Connection is fully setup - initialize the stack
  446                  */
  447                 cvp->cvc_state = CVCS_INIT;
  448                 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
  449                         cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
  450                 if (err2)
  451                         panic("atm_cm_connect: init");
  452 
  453                 if (cvp->cvc_flags & CVCF_ABORTING) {
  454                         /*
  455                          * Someone on the stack bailed out...schedule the 
  456                          * VCC and stack termination
  457                          */
  458                         atm_cm_closevc(cvp);
  459                         err = EFAULT;
  460                 } else {
  461                         /*
  462                          * Everything looks fine from here
  463                          */
  464                         cvp->cvc_state = CVCS_ACTIVE;
  465                         cop->co_state = COS_ACTIVE;
  466                 }
  467                 break;
  468 
  469         case CALL_FAILED:
  470                 /*
  471                  * Terminate stack and clean up before we leave
  472                  */
  473                 cvp->cvc_state = CVCS_CLEAR;
  474                 atm_cm_closevc(cvp);
  475                 break;
  476 
  477         case CALL_PROCEEDING:
  478                 /*
  479                  * We'll just wait for final call status
  480                  */
  481                 cop->co_state = COS_OUTCONN;
  482                 err = EINPROGRESS;
  483                 break;
  484 
  485         default:
  486                 panic("atm_cm_connect: setup");
  487         }
  488 
  489 donex:
  490         (void) splx(s);
  491 
  492 done:
  493         if (err && err != EINPROGRESS) {
  494                 /*
  495                  * Undo any partial setup stuff
  496                  */
  497                 if (cop)
  498                         uma_zfree(atm_connection_zone, cop);
  499         } else {
  500                 /*
  501                  * Finish connection setup
  502                  */
  503                 s = splnet();
  504                 cvp->cvc_flags |= CVCF_CONNQ;
  505                 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
  506                 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
  507                 (void) splx(s);
  508                 *copp = cop;
  509         }
  510         return (err);
  511 }
  512 
  513 
  514 /*
  515  * Listen for Incoming ATM Calls
  516  * 
  517  * Called by an endpoint service in order to indicate its willingness to
  518  * accept certain incoming calls.  The types of calls which the endpoint
  519  * is prepared to accept are specified in the Atm_attributes parameter.
  520  *
  521  * For each call which meets the criteria specified by the endpoint, the
  522  * endpoint service will receive an incoming call notification via the
  523  * endpoint's ep_incoming() function.
  524  *
  525  * To cancel the listening connection, the endpoint user should invoke 
  526  * atm_cm_release().
  527  *
  528  * Arguments:
  529  *      epp     pointer to endpoint definition structure
  530  *      token   endpoint's listen instance token
  531  *      ap      pointer to listening connection attributes
  532  *      copp    pointer to location to return allocated connection block
  533  *
  534  * Returns:
  535  *      0       listening connection installed
  536  *      errno   listen failed - reason indicated
  537  *
  538  */
  539 int
  540 atm_cm_listen(epp, token, ap, copp)
  541         Atm_endpoint    *epp;
  542         void            *token;
  543         Atm_attributes  *ap;
  544         Atm_connection  **copp;
  545 {
  546         Atm_connection  *cop;
  547         int             s, err = 0;
  548 
  549         *copp = NULL;
  550 
  551         /*
  552          * Get a connection block
  553          */
  554         cop = uma_zalloc(atm_connection_zone, M_WAITOK);
  555         if (cop == NULL)
  556                 return (ENOMEM);
  557 
  558         /*
  559          * Initialize connection info
  560          */
  561         cop->co_endpt = epp;
  562         cop->co_toku = token;
  563         cop->co_mxh = cop;
  564 
  565         /*
  566          * Validate and extract useful attribute information
  567          */
  568 
  569         /*
  570          * Check out Data API
  571          */
  572         switch (ap->api) {
  573 
  574         case CMAPI_CPCS:
  575         case CMAPI_SAAL:
  576         case CMAPI_SSCOP:
  577                 break;
  578 
  579         default:
  580                 err = EINVAL;
  581                 goto done;
  582         }
  583 
  584         /*
  585          * AAL Attributes
  586          */
  587         switch (ap->aal.tag) {
  588 
  589         case T_ATM_PRESENT:
  590 
  591                 switch (ap->aal.type) {
  592 
  593                 case ATM_AAL5:
  594                 case ATM_AAL3_4:
  595                         break;
  596 
  597                 default:
  598                         err = EINVAL;
  599                         goto done;
  600                 }
  601                 break;
  602 
  603         case T_ATM_ABSENT:
  604         case T_ATM_ANY:
  605                 break;
  606 
  607         default:
  608                 err = EINVAL;
  609                 goto done;
  610         }
  611 
  612         /*
  613          * Broadband High Layer Information Attributes
  614          */
  615         switch (ap->bhli.tag) {
  616 
  617         case T_ATM_PRESENT:
  618         case T_ATM_ABSENT:
  619         case T_ATM_ANY:
  620                 break;
  621 
  622         default:
  623                 err = EINVAL;
  624                 goto done;
  625         }
  626 
  627         /*
  628          * Broadband Low Layer Information Attributes
  629          */
  630         switch (ap->blli.tag_l2) {
  631 
  632         case T_ATM_PRESENT:
  633         case T_ATM_ABSENT:
  634         case T_ATM_ANY:
  635                 break;
  636 
  637         default:
  638                 err = EINVAL;
  639                 goto done;
  640         }
  641 
  642         switch (ap->blli.tag_l3) {
  643 
  644         case T_ATM_PRESENT:
  645         case T_ATM_ABSENT:
  646         case T_ATM_ANY:
  647                 break;
  648 
  649         default:
  650                 err = EINVAL;
  651                 goto done;
  652         }
  653 
  654         /*
  655          * Logical Link Control Attributes
  656          */
  657         switch (ap->llc.tag) {
  658 
  659         case T_ATM_PRESENT:
  660                 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
  661                     (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
  662                     (ap->blli.v.layer_2_protocol.ID.simple_ID != 
  663                                 T_ATM_BLLI2_I8802) ||
  664                     (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
  665                     (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
  666                         err = EINVAL;
  667                         goto done;
  668                 }
  669                 cop->co_mpx = ATM_ENC_LLC;
  670                 cop->co_llc = ap->llc;
  671                 break;
  672 
  673         case T_ATM_ABSENT:
  674         case T_ATM_ANY:
  675                 cop->co_mpx = ATM_ENC_NULL;
  676                 break;
  677 
  678         default:
  679                 err = EINVAL;
  680                 goto done;
  681         }
  682 
  683         /*
  684          * Called Party Attributes
  685          */
  686         switch (ap->called.tag) {
  687 
  688         case T_ATM_PRESENT:
  689                 switch (ap->called.addr.address_format) {
  690 
  691                 case T_ATM_ABSENT:
  692                         ap->called.tag = T_ATM_ABSENT;
  693                         break;
  694 
  695                 case T_ATM_PVC_ADDR:
  696                         err = EINVAL;
  697                         goto done;
  698                 }
  699                 break;
  700 
  701         case T_ATM_ABSENT:
  702         case T_ATM_ANY:
  703                 break;
  704 
  705         default:
  706                 err = EINVAL;
  707                 goto done;
  708         }
  709 
  710         /*
  711          * Get an attribute block and save listening attributes
  712          */
  713         cop->co_lattr = uma_zalloc(atm_attributes_zone, M_WAITOK | M_ZERO);
  714         if (cop->co_lattr == NULL) {
  715                 err = ENOMEM;
  716                 goto done;
  717         }
  718         *cop->co_lattr = *ap;
  719 
  720         /*
  721          * Now try to register the listening connection
  722          */
  723         s = splnet();
  724         if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
  725                 /*
  726                  * Can't have matching listeners
  727                  */
  728                 err = EADDRINUSE;
  729                 goto donex;
  730         }
  731         cop->co_state = COS_LISTEN;
  732         LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
  733 
  734 donex:
  735         (void) splx(s);
  736 
  737 done:
  738         if (err) {
  739                 /*
  740                  * Undo any partial setup stuff
  741                  */
  742                 if (cop) {
  743                         if (cop->co_lattr)
  744                                 uma_zfree(atm_attributes_zone, cop->co_lattr);
  745                         uma_zfree(atm_connection_zone, cop);
  746                 }
  747         } else {
  748                 /*
  749                  * Finish connection setup
  750                  */
  751                 *copp = cop;
  752         }
  753         return (err);
  754 }
  755 
  756 
  757 /*
  758  * Add to LLC Connection
  759  * 
  760  * Called by an endpoint service to create a new Connection Manager API
  761  * instance to be associated with an LLC-multiplexed connection instance
  762  * which has been previously created.  The endpoint provided token will
  763  * be used in all further CM -> endpoint function calls, and the returned
  764  * connection block pointer must be used in all subsequent endpoint -> CM
  765  * function calls.
  766  *
  767  * If the return indicates that the connection setup has been immediately
  768  * successful, then the connection is ready for data transmission.
  769  *
  770  * If the return indicates that the connection setup is still in progress,
  771  * then the endpoint must wait for notification from the Connection Manager
  772  * indicating the final status of the call setup.  If the call setup completes
  773  * successfully, then a "call connected" notification will be sent to the
  774  * endpoint by the Connection Manager.  If the call setup fails, then the
  775  * endpoint will receive a "call cleared" notification.
  776  *
  777  * All connection instances must be freed with an atm_cm_release() call.
  778  *
  779  * Arguments:
  780  *      epp     pointer to endpoint definition structure
  781  *      token   endpoint's connection instance token
  782  *      llc     pointer to llc attributes for new connection
  783  *      ecop    pointer to existing connection block
  784  *      copp    pointer to location to return allocated connection block
  785  *
  786  * Returns:
  787  *      0       connection has been successfully established
  788  *      EINPROGRESS     connection establishment is in progress
  789  *      errno   addllc failed - reason indicated
  790  *
  791  */
  792 int
  793 atm_cm_addllc(epp, token, llc, ecop, copp)
  794         Atm_endpoint    *epp;
  795         void            *token;
  796         struct attr_llc *llc;
  797         Atm_connection  *ecop;
  798         Atm_connection  **copp;
  799 {
  800         Atm_connection  *cop, *cop2;
  801         Atm_connvc      *cvp;
  802         int             s, err;
  803 
  804         *copp = NULL;
  805 
  806         /*
  807          * Check out requested LLC attributes
  808          */
  809         if ((llc->tag != T_ATM_PRESENT) ||
  810             ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
  811             (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
  812             (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
  813                 return (EINVAL);
  814 
  815         /*
  816          * Get a connection block
  817          */
  818         cop = uma_zalloc(atm_connection_zone, M_WAITOK);
  819         if (cop == NULL)
  820                 return (ENOMEM);
  821 
  822         /*
  823          * Initialize connection info
  824          */
  825         cop->co_endpt = epp;
  826         cop->co_toku = token;
  827         cop->co_llc = *llc;
  828 
  829         s = splnet();
  830 
  831         /*
  832          * Ensure that supplied connection is really valid
  833          */
  834         cop2 = NULL;
  835         for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
  836                         cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
  837                 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
  838                         if (ecop == cop2)
  839                                 break;
  840                 }
  841                 if (cop2)
  842                         break;
  843         }
  844         if (cop2 == NULL) {
  845                 err = ENOENT;
  846                 goto done;
  847         }
  848 
  849         switch (ecop->co_state) {
  850 
  851         case COS_OUTCONN:
  852         case COS_INACCEPT:
  853                 err = EINPROGRESS;
  854                 break;
  855 
  856         case COS_ACTIVE:
  857                 err = 0;
  858                 break;
  859 
  860         default:
  861                 err = EINVAL;
  862                 goto done;
  863         }
  864 
  865         /*
  866          * Connection must be LLC multiplexed and shared
  867          */
  868         if ((ecop->co_mpx != ATM_ENC_LLC) ||
  869             ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
  870                 err = EINVAL;
  871                 goto done;
  872         }
  873 
  874         /*
  875          * This new LLC header must be unique for this VCC
  876          */
  877         cop2 = ecop->co_mxh;
  878         while (cop2) {
  879                 int     i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
  880 
  881                 if (bcmp(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
  882                         err = EINVAL;
  883                         goto done;
  884                 }
  885 
  886                 cop2 = cop2->co_next;
  887         }
  888 
  889         /*
  890          * Everything seems to check out
  891          */
  892         cop->co_flags = ecop->co_flags;
  893         cop->co_state = ecop->co_state;
  894         cop->co_mpx = ecop->co_mpx;
  895         cop->co_connvc = ecop->co_connvc;
  896 
  897         LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
  898         cop->co_mxh = ecop->co_mxh;
  899 
  900 done:
  901         (void) splx(s);
  902 
  903         if (err && err != EINPROGRESS) {
  904                 /*
  905                  * Undo any partial setup stuff
  906                  */
  907                 if (cop)
  908                         uma_zfree(atm_connection_zone, cop);
  909         } else {
  910                 /*
  911                  * Pass new connection back to caller
  912                  */
  913                 *copp = cop;
  914         }
  915         return (err);
  916 }
  917 
  918 
  919 /*
  920  * XXX
  921  * 
  922  * Arguments:
  923  *      cop     pointer to connection block
  924  *      id      identifier for party to be added
  925  *      addr    address of party to be added
  926  *
  927  * Returns:
  928  *      0       addparty successful
  929  *      errno   addparty failed - reason indicated
  930  *
  931  */
  932 int
  933 atm_cm_addparty(cop, id, addr)
  934         Atm_connection  *cop;
  935         int             id;
  936         struct t_atm_sap        *addr;
  937 {
  938         return (0);
  939 }
  940 
  941 
  942 /*
  943  * XXX
  944  * 
  945  * Arguments:
  946  *      cop     pointer to connection block
  947  *      id      identifier for party to be added
  948  *      cause   pointer to cause of drop
  949  *
  950  * Returns:
  951  *      0       dropparty successful
  952  *      errno   dropparty failed - reason indicated
  953  *
  954  */
  955 int
  956 atm_cm_dropparty(cop, id, cause)
  957         Atm_connection  *cop;
  958         int             id;
  959         struct t_atm_cause      *cause;
  960 {
  961         return (0);
  962 }
  963 
  964 
  965 /*
  966  * Release Connection Resources
  967  * 
  968  * Called by the endpoint service in order to terminate an ATM connection 
  969  * and to release all system resources for the connection.  This function
  970  * must be called for every allocated connection instance and must only 
  971  * be called by the connection's owner.
  972  *
  973  * Arguments:
  974  *      cop     pointer to connection block
  975  *      cause   pointer to cause of release
  976  *
  977  * Returns:
  978  *      0       release successful
  979  *      errno   release failed - reason indicated
  980  *
  981  */
  982 int
  983 atm_cm_release(cop, cause)
  984         Atm_connection  *cop;
  985         struct t_atm_cause      *cause;
  986 {
  987         Atm_connvc      *cvp;
  988         int             s;
  989 
  990         s = splnet();
  991 
  992         /*
  993          * First, a quick state validation check
  994          */
  995         switch (cop->co_state) {
  996 
  997         case COS_OUTCONN:
  998         case COS_LISTEN:
  999         case COS_INACCEPT:
 1000         case COS_ACTIVE:
 1001         case COS_CLEAR:
 1002                 /*
 1003                  * Break link to user
 1004                  */
 1005                 cop->co_toku = NULL;
 1006                 break;
 1007 
 1008         case COS_INCONN:
 1009                 (void) splx(s);
 1010                 return (EFAULT);
 1011 
 1012         default:
 1013                 panic("atm_cm_release: bogus conn state");
 1014         }
 1015 
 1016         /*
 1017          * Check out the VCC state too
 1018          */
 1019         if ((cvp = cop->co_connvc) != NULL) {
 1020 
 1021                 switch (cvp->cvc_state) {
 1022 
 1023                 case CVCS_SETUP:
 1024                 case CVCS_INIT:
 1025                 case CVCS_ACCEPT:
 1026                 case CVCS_ACTIVE:
 1027                         break;
 1028 
 1029                 case CVCS_INCOMING:
 1030                         (void) splx(s);
 1031                         return (EFAULT);
 1032 
 1033                 case CVCS_CLEAR:
 1034                         (void) splx(s);
 1035                         return (EALREADY);
 1036 
 1037                 default:
 1038                         panic("atm_cm_release: bogus connvc state");
 1039                 }
 1040 
 1041                 /*
 1042                  * If we're the only connection, terminate the VCC
 1043                  */
 1044                 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
 1045                         cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
 1046                         cvp->cvc_attr.cause.v = *cause;
 1047                         atm_cm_closevc(cvp);
 1048                 }
 1049         }
 1050 
 1051         /*
 1052          * Now get rid of the connection
 1053          */
 1054         atm_cm_closeconn(cop, cause);
 1055 
 1056         return (0);
 1057 }
 1058 
 1059 
 1060 /*
 1061  * Abort an ATM Connection VCC
 1062  * 
 1063  * This function allows any non-owner kernel entity to request an 
 1064  * immediate termination of an ATM VCC.  This will normally be called
 1065  * when encountering a catastrophic error condition that cannot be 
 1066  * resolved via the available stack protocols.  The connection manager 
 1067  * will schedule the connection's termination, including notifying the 
 1068  * connection owner of the termination.  
 1069  *
 1070  * This function should only be called by a stack entity instance.  After 
 1071  * calling the function, the caller should set a protocol state which just 
 1072  * waits for a <sap>_TERM stack command to be delivered.
 1073  *
 1074  * Arguments:
 1075  *      cvp     pointer to connection VCC block
 1076  *      cause   pointer to cause of abort
 1077  *
 1078  * Returns:
 1079  *      0       abort successful
 1080  *      errno   abort failed - reason indicated
 1081  *
 1082  */
 1083 int
 1084 atm_cm_abort(cvp, cause)
 1085         Atm_connvc      *cvp;
 1086         struct t_atm_cause      *cause;
 1087 {
 1088         ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
 1089                 cvp, cause->cause_value);
 1090 
 1091         /*
 1092          * Note that we're aborting
 1093          */
 1094         cvp->cvc_flags |= CVCF_ABORTING;
 1095 
 1096         switch (cvp->cvc_state) {
 1097 
 1098         case CVCS_INIT:
 1099                 /*
 1100                  * In-line code will handle this
 1101                  */
 1102                 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
 1103                 cvp->cvc_attr.cause.v = *cause;
 1104                 break;
 1105 
 1106         case CVCS_SETUP:
 1107         case CVCS_ACCEPT:
 1108         case CVCS_ACTIVE:
 1109                 /*
 1110                  * Schedule connection termination, since we want
 1111                  * to avoid any sequencing interactions
 1112                  */
 1113                 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
 1114                 cvp->cvc_attr.cause.v = *cause;
 1115                 CVC_TIMER(cvp, 0);
 1116                 break;
 1117 
 1118         case CVCS_REJECT:
 1119         case CVCS_RELEASE:
 1120         case CVCS_CLEAR:
 1121         case CVCS_TERM:
 1122                 /*
 1123                  * Ignore abort, as we're already terminating
 1124                  */
 1125                 break;
 1126 
 1127         default:
 1128                 log(LOG_ERR,
 1129                         "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
 1130                         cvp, cvp->cvc_state);
 1131         }
 1132         return (0);
 1133 }
 1134 
 1135 
 1136 /*
 1137  * Incoming ATM Call Received
 1138  * 
 1139  * Called by a signalling manager to indicate that a new call request has
 1140  * been received.  This function will allocate and initialize the connection
 1141  * manager control blocks and queue this call request.  The call request 
 1142  * processing function, atm_cm_procinq(), will be scheduled to perform the
 1143  * call processing.
 1144  *
 1145  * Arguments:
 1146  *      vcp     pointer to incoming call's VCC control block
 1147  *      ap      pointer to incoming call's attributes
 1148  *
 1149  * Returns:
 1150  *      0       call queuing successful
 1151  *      errno   call queuing failed - reason indicated
 1152  *
 1153  */
 1154 int
 1155 atm_cm_incoming(vcp, ap)
 1156         struct vccb     *vcp;
 1157         Atm_attributes  *ap;
 1158 {
 1159         Atm_connvc      *cvp;
 1160         int             s, err;
 1161 
 1162 
 1163         /*
 1164          * Do some minimal attribute validation
 1165          */
 1166 
 1167         /*
 1168          * Must specify a network interface
 1169          */
 1170         if (ap->nif == NULL)
 1171                 return (EINVAL);
 1172 
 1173         /*
 1174          * AAL Attributes
 1175          */
 1176         if ((ap->aal.tag != T_ATM_PRESENT) ||
 1177             ((ap->aal.type != ATM_AAL5) &&
 1178              (ap->aal.type != ATM_AAL3_4)))
 1179                 return (EINVAL);
 1180 
 1181         /*
 1182          * Traffic Descriptor Attributes
 1183          */
 1184         if ((ap->traffic.tag != T_ATM_PRESENT) &&
 1185             (ap->traffic.tag != T_ATM_ABSENT))
 1186                 return (EINVAL);
 1187 
 1188         /*
 1189          * Broadband Bearer Attributes
 1190          */
 1191         if ((ap->bearer.tag != T_ATM_PRESENT) ||
 1192             ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
 1193              (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
 1194                 return (EINVAL);
 1195 
 1196         /*
 1197          * Broadband High Layer Attributes
 1198          */
 1199         if ((ap->bhli.tag != T_ATM_PRESENT) &&
 1200             (ap->bhli.tag != T_ATM_ABSENT))
 1201                 return (EINVAL);
 1202 
 1203         /*
 1204          * Broadband Low Layer Attributes
 1205          */
 1206         if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
 1207             (ap->blli.tag_l2 != T_ATM_ABSENT))
 1208                 return (EINVAL);
 1209         if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
 1210             (ap->blli.tag_l3 != T_ATM_ABSENT))
 1211                 return (EINVAL);
 1212 
 1213         /*
 1214          * Logical Link Control Attributes
 1215          */
 1216         if (ap->llc.tag == T_ATM_PRESENT)
 1217                 return (EINVAL);
 1218         ap->llc.tag = T_ATM_ANY;
 1219 
 1220         /*
 1221          * Called Party Attributes
 1222          */
 1223         if ((ap->called.tag != T_ATM_PRESENT) ||
 1224             (ap->called.addr.address_format == T_ATM_ABSENT))
 1225                 return (EINVAL);
 1226         if (ap->called.tag == T_ATM_ABSENT) {
 1227                 ap->called.addr.address_format = T_ATM_ABSENT;
 1228                 ap->called.addr.address_length = 0;
 1229                 ap->called.subaddr.address_format = T_ATM_ABSENT;
 1230                 ap->called.subaddr.address_length = 0;
 1231         }
 1232 
 1233         /*
 1234          * Calling Party Attributes
 1235          */
 1236         if ((ap->calling.tag != T_ATM_PRESENT) &&
 1237             (ap->calling.tag != T_ATM_ABSENT))
 1238                 return (EINVAL);
 1239         if (ap->calling.tag == T_ATM_ABSENT) {
 1240                 ap->calling.addr.address_format = T_ATM_ABSENT;
 1241                 ap->calling.addr.address_length = 0;
 1242                 ap->calling.subaddr.address_format = T_ATM_ABSENT;
 1243                 ap->calling.subaddr.address_length = 0;
 1244         }
 1245 
 1246         /*
 1247          * Quality of Service Attributes
 1248          */
 1249         if (ap->qos.tag != T_ATM_PRESENT)
 1250                 return (EINVAL);
 1251 
 1252         /*
 1253          * Transit Network Attributes
 1254          */
 1255         if ((ap->transit.tag != T_ATM_PRESENT) &&
 1256             (ap->transit.tag != T_ATM_ABSENT))
 1257                 return (EINVAL);
 1258 
 1259         /*
 1260          * Cause Attributes
 1261          */
 1262         if ((ap->cause.tag != T_ATM_PRESENT) &&
 1263             (ap->cause.tag != T_ATM_ABSENT))
 1264                 return (EINVAL);
 1265 
 1266         /*
 1267          * Get a connection VCC block
 1268          */
 1269         cvp = uma_zalloc(atm_connvc_zone, M_WAITOK);
 1270         if (cvp == NULL) {
 1271                 err = ENOMEM;
 1272                 goto fail;
 1273         }
 1274 
 1275         /*
 1276          * Initialize the control block
 1277          */
 1278         cvp->cvc_vcc = vcp;
 1279         cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
 1280         cvp->cvc_attr = *ap;
 1281         cvp->cvc_state = CVCS_INCOMING;
 1282 
 1283         /*
 1284          * Control queue length
 1285          */
 1286         s = splnet();
 1287         if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
 1288                 (void) splx(s);
 1289                 err = EBUSY;
 1290                 goto fail;
 1291         }
 1292 
 1293         /*
 1294          * Queue request and schedule call processing function
 1295          */
 1296         cvp->cvc_flags |= CVCF_INCOMQ;
 1297         ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
 1298         if (atm_incoming_qlen++ == 0) {
 1299                 timeout(atm_cm_procinq, (void *)0, 0);
 1300         }
 1301 
 1302         /*
 1303          * Link for signalling manager
 1304          */
 1305         vcp->vc_connvc = cvp;
 1306 
 1307         (void) splx(s);
 1308 
 1309         return (0);
 1310 
 1311 fail:
 1312         /*
 1313          * Free any resources
 1314          */
 1315         if (cvp)
 1316                 uma_zfree(atm_connvc_zone, cvp);
 1317         return (err);
 1318 }
 1319 
 1320 
 1321 /*
 1322  * VCC Connected Notification
 1323  * 
 1324  * This function is called by a signalling manager as notification that a
 1325  * VCC call setup has been successful.
 1326  *
 1327  * Arguments:
 1328  *      cvp     pointer to connection VCC block
 1329  *
 1330  * Returns:
 1331  *      none
 1332  *
 1333  */
 1334 void
 1335 atm_cm_connected(cvp)
 1336         Atm_connvc      *cvp;
 1337 {
 1338         Atm_connection  *cop, *cop2;
 1339         KBuffer         *m;
 1340         int             s, err;
 1341 
 1342         s = splnet();
 1343 
 1344         /*
 1345          * Validate connection vcc
 1346          */
 1347         switch (cvp->cvc_state) {
 1348 
 1349         case CVCS_SETUP:
 1350                 /*
 1351                  * Initialize the stack
 1352                  */
 1353                 cvp->cvc_state = CVCS_INIT;
 1354                 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
 1355                                 cvp->cvc_lower, cvp->cvc_tokl,
 1356                                 cvp, cvp->cvc_attr.api_init, 0, err);
 1357                 if (err)
 1358                         panic("atm_cm_connected: init");
 1359 
 1360                 if (cvp->cvc_flags & CVCF_ABORTING) {
 1361                         /*
 1362                          * Someone on the stack bailed out...notify all of the
 1363                          * connections and schedule the VCC termination
 1364                          */
 1365                         cop = cvp->cvc_conn;
 1366                         while (cop) {
 1367                                 cop2 = cop->co_next;
 1368                                 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
 1369                                 cop = cop2;
 1370                         }
 1371                         atm_cm_closevc(cvp);
 1372                         (void) splx(s);
 1373                         return;
 1374                 }
 1375                 break;
 1376 
 1377         case CVCS_ACCEPT:
 1378                 /*
 1379                  * Stack already initialized
 1380                  */
 1381                 break;
 1382 
 1383         default:
 1384                 panic("atm_cm_connected: connvc state");
 1385         }
 1386 
 1387         /*
 1388          * VCC is ready for action
 1389          */
 1390         cvp->cvc_state = CVCS_ACTIVE;
 1391 
 1392         /*
 1393          * Notify all connections that the call has completed
 1394          */
 1395         cop = cvp->cvc_conn;
 1396         while (cop) {
 1397                 cop2 = cop->co_next;
 1398 
 1399                 switch (cop->co_state) {
 1400 
 1401                 case COS_OUTCONN:
 1402                 case COS_INACCEPT:
 1403                         cop->co_state = COS_ACTIVE;
 1404                         (*cop->co_endpt->ep_connected)(cop->co_toku);
 1405                         break;
 1406 
 1407                 case COS_ACTIVE:
 1408                         /*
 1409                          * May get here if an ep_connected() call (from
 1410                          * above) results in an atm_cm_addllc() call for 
 1411                          * the just connected connection.
 1412                          */
 1413                         break;
 1414 
 1415                 default:
 1416                         panic("atm_cm_connected: connection state");
 1417                 }
 1418 
 1419                 cop = cop2;
 1420         }
 1421 
 1422         (void) splx(s);
 1423 
 1424         /*
 1425          * Input any queued packets
 1426          */
 1427         while ((m = cvp->cvc_rcvq) != NULL) {
 1428                 cvp->cvc_rcvq = KB_QNEXT(m);
 1429                 cvp->cvc_rcvqlen--;
 1430                 KB_QNEXT(m) = NULL;
 1431 
 1432                 /*
 1433                  * Currently only supported for CPCS API
 1434                  */
 1435                 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (intptr_t)m, 0);
 1436         }
 1437 
 1438         return;
 1439 }
 1440 
 1441 
 1442 /*
 1443  * VCC Cleared Notification
 1444  * 
 1445  * This function is called by a signalling manager as notification that a
 1446  * VCC call has been cleared.  The cause information describing the reason
 1447  * for the call clearing will be contained in the connection VCC attributes.
 1448  *
 1449  * Arguments:
 1450  *      cvp     pointer to connection VCC block
 1451  *
 1452  * Returns:
 1453  *      none
 1454  *
 1455  */
 1456 void
 1457 atm_cm_cleared(cvp)
 1458         Atm_connvc      *cvp;
 1459 {
 1460         Atm_connection  *cop, *cop2;
 1461         int             s;
 1462 
 1463         KASSERT((cvp->cvc_state != CVCS_FREE) && (cvp->cvc_state < CVCS_CLEAR),
 1464             ("atm_cm_cleared: state sanity check failed"));
 1465 
 1466         cvp->cvc_state = CVCS_CLEAR;
 1467         s = splnet();
 1468 
 1469         /*
 1470          * Terminate all connections
 1471          */
 1472         cop = cvp->cvc_conn;
 1473         while (cop) {
 1474                 cop2 = cop->co_next;
 1475                 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
 1476                 cop = cop2;
 1477         }
 1478 
 1479         /*
 1480          * Clean up connection VCC
 1481          */
 1482         atm_cm_closevc(cvp);
 1483 
 1484         (void) splx(s);
 1485 
 1486         return;
 1487 }
 1488 
 1489 
 1490 /*
 1491  * Process Incoming Call Queue
 1492  * 
 1493  * This function is scheduled by atm_cm_incoming() in order to process
 1494  * all the entries on the incoming call queue.
 1495  *
 1496  * Arguments:
 1497  *      arg     argument passed on timeout() call
 1498  *
 1499  * Returns:
 1500  *      none
 1501  *
 1502  */
 1503 static KTimeout_ret
 1504 atm_cm_procinq(arg)
 1505         void    *arg;
 1506 {
 1507         Atm_connvc      *cvp;
 1508         int             cnt = 0, s;
 1509 
 1510         /*
 1511          * Only process incoming calls up to our quota
 1512          */
 1513         while (cnt++ < ATM_CALLQ_MAX) {
 1514 
 1515                 s = splnet();
 1516 
 1517                 /*
 1518                  * Get next awaiting call
 1519                  */
 1520                 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
 1521                 if (cvp == NULL) {
 1522                         (void) splx(s);
 1523                         break;
 1524                 }
 1525                 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
 1526                 atm_incoming_qlen--;
 1527                 cvp->cvc_flags &= ~CVCF_INCOMQ;
 1528 
 1529                 /*
 1530                  * Handle the call
 1531                  */
 1532                 atm_cm_incall(cvp);
 1533 
 1534                 (void) splx(s);
 1535         }
 1536 
 1537         /*
 1538          * If we've expended our quota, reschedule ourselves
 1539          */
 1540         if (cnt >= ATM_CALLQ_MAX)
 1541                 timeout(atm_cm_procinq, (void *)0, 0);
 1542 }
 1543 
 1544 
 1545 /*
 1546  * Process Incoming Call
 1547  * 
 1548  * This function will search through the listening queue and try to find
 1549  * matching endpoint(s) for the incoming call.  If we find any, we will
 1550  * notify the endpoint service(s) of the incoming call and will then
 1551  * notify the signalling manager to progress the call to an active status.
 1552  * 
 1553  * If there are no listeners for the call, the signalling manager will be
 1554  * notified of a call rejection.
 1555  *
 1556  * Called at splnet.
 1557  *
 1558  * Arguments:
 1559  *      cvp     pointer to connection VCC for incoming call
 1560  *
 1561  * Returns:
 1562  *      none
 1563  *
 1564  */
 1565 static void
 1566 atm_cm_incall(cvp)
 1567         Atm_connvc      *cvp;
 1568 {
 1569         Atm_connection  *cop, *lcop, *hcop;
 1570         Atm_attributes  attr;
 1571         int             err;
 1572 
 1573         hcop = NULL;
 1574         lcop = NULL;
 1575         cop = NULL;
 1576         attr = cvp->cvc_attr;
 1577 
 1578         /*
 1579          * Look for matching listeners
 1580          */
 1581         while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
 1582 
 1583                 if (cop == NULL) {
 1584                         /*
 1585                          * Need a new connection block
 1586                          */
 1587                         cop = uma_zalloc(atm_connection_zone, M_WAITOK);
 1588                         if (cop == NULL) {
 1589                                 cvp->cvc_attr.cause = atm_cause_tmpl;
 1590                                 cvp->cvc_attr.cause.v.cause_value =
 1591                                                 T_ATM_CAUSE_TEMPORARY_FAILURE;
 1592                                 goto fail;
 1593                         }
 1594                 }
 1595 
 1596                 /*
 1597                  * Initialize connection from listener and incoming call
 1598                  */
 1599                 cop->co_mxh = NULL;
 1600                 cop->co_state = COS_INCONN;
 1601                 cop->co_mpx = lcop->co_mpx;
 1602                 cop->co_endpt = lcop->co_endpt;
 1603                 cop->co_llc = lcop->co_llc;
 1604 
 1605                 switch (attr.bearer.v.connection_configuration) {
 1606 
 1607                 case T_ATM_1_TO_1:
 1608                         cop->co_flags |= COF_P2P;
 1609                         break;
 1610 
 1611                 case T_ATM_1_TO_MANY:
 1612                         /* Not supported */
 1613                         cop->co_flags |= COF_P2MP;
 1614                         cvp->cvc_attr.cause = atm_cause_tmpl;
 1615                         cvp->cvc_attr.cause.v.cause_value =
 1616                                 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
 1617                         goto fail;
 1618                 }
 1619 
 1620                 /*
 1621                  * Notify endpoint of incoming call
 1622                  */
 1623                 err = (*cop->co_endpt->ep_incoming)
 1624                         (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
 1625 
 1626                 if (err == 0) {
 1627 
 1628                         /*
 1629                          * Endpoint has accepted the call
 1630                          *
 1631                          * Setup call attributes
 1632                          */
 1633                         if (hcop == NULL) {
 1634                                 cvp->cvc_attr.api = lcop->co_lattr->api;
 1635                                 cvp->cvc_attr.api_init =
 1636                                         lcop->co_lattr->api_init;
 1637                                 cvp->cvc_attr.llc = lcop->co_lattr->llc;
 1638                         }
 1639                         cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
 1640                                 lcop->co_lattr->headin);
 1641 
 1642                         /*
 1643                          * Setup connection info and queueing
 1644                          */
 1645                         cop->co_state = COS_INACCEPT;
 1646                         cop->co_connvc = cvp;
 1647                         LINK2TAIL(cop, Atm_connection, hcop, co_next);
 1648                         cop->co_mxh = hcop;
 1649 
 1650                         /*
 1651                          * Need a new connection block next time around
 1652                          */
 1653                         cop = NULL;
 1654 
 1655                 } else {
 1656                         /*
 1657                          * Endpoint refuses call
 1658                          */
 1659                         goto fail;
 1660                 }
 1661         }
 1662 
 1663         /*
 1664          * We're done looking for listeners
 1665          */
 1666         if (hcop) {
 1667                 /*
 1668                  * Someone actually wants the call, so notify
 1669                  * the signalling manager to continue
 1670                  */
 1671                 cvp->cvc_flags |= CVCF_CONNQ;
 1672                 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
 1673                 if (atm_cm_accept(cvp, hcop))
 1674                         goto fail;
 1675 
 1676         } else {
 1677                 /*
 1678                  * Nobody around to take the call
 1679                  */
 1680                 cvp->cvc_attr.cause = atm_cause_tmpl;
 1681                 cvp->cvc_attr.cause.v.cause_value =
 1682                                 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
 1683                 goto fail;
 1684         }
 1685 
 1686         /*
 1687          * Clean up loose ends
 1688          */
 1689         if (cop)
 1690                 uma_zfree(atm_connection_zone, cop);
 1691 
 1692         /*
 1693          * Call has been accepted
 1694          */
 1695         return;
 1696 
 1697 fail:
 1698         /*
 1699          * Call failed - notify any endpoints of the call failure
 1700          */
 1701 
 1702         /*
 1703          * Clean up loose ends
 1704          */
 1705         if (cop)
 1706                 uma_zfree(atm_connection_zone, cop);
 1707 
 1708         if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
 1709                 cvp->cvc_attr.cause = atm_cause_tmpl;
 1710                 cvp->cvc_attr.cause.v.cause_value =
 1711                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
 1712         }
 1713         cop = hcop;
 1714         while (cop) {
 1715                 Atm_connection  *cop2 = cop->co_next;
 1716                 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
 1717                 cop = cop2;
 1718         }
 1719 
 1720         /*
 1721          * Tell the signalling manager to reject the call
 1722          */
 1723         atm_cm_closevc(cvp);
 1724 
 1725         return;
 1726 }
 1727 
 1728 
 1729 /*
 1730  * Accept an Incoming ATM Call
 1731  * 
 1732  * Some endpoint service(s) wants to accept an incoming call, so the
 1733  * signalling manager will be notified to attempt to progress the call
 1734  * to an active status.
 1735  *
 1736  * If the signalling manager indicates that connection activation has 
 1737  * been immediately successful, then all of the endpoints will be notified
 1738  * that the connection is ready for data transmission.
 1739  * 
 1740  * If the return indicates that connection activation is still in progress,
 1741  * then the endpoints must wait for notification from the Connection Manager
 1742  * indicating the final status of the call setup.  If the call setup completes
 1743  * successfully, then a "call connected" notification will be sent to the
 1744  * endpoints by the Connection Manager.  If the call setup fails, then the
 1745  * endpoints will receive a "call cleared" notification.
 1746  *
 1747  * Called at splnet.
 1748  *
 1749  * Arguments:
 1750  *      cvp     pointer to connection VCC for incoming call
 1751  *      cop     pointer to head of accepted connections
 1752  *
 1753  * Returns:
 1754  *      0       connection has been successfully activated
 1755  *      errno   accept failed - reason indicated
 1756  *
 1757  */
 1758 static int
 1759 atm_cm_accept(cvp, cop)
 1760         Atm_connvc      *cvp;
 1761         Atm_connection  *cop;
 1762 {
 1763         struct stack_list       sl;
 1764         void            (*upf)(int, void *, intptr_t, intptr_t);
 1765         int             sli, err, err2;
 1766 
 1767 
 1768         /*
 1769          * Link vcc to connections
 1770          */
 1771         cvp->cvc_conn = cop;
 1772 
 1773         /*
 1774          * Initialize stack list index
 1775          */
 1776         sli = 0;
 1777 
 1778         /*
 1779          * Check out Data API
 1780          */
 1781         switch (cvp->cvc_attr.api) {
 1782 
 1783         case CMAPI_CPCS:
 1784                 upf = atm_cm_cpcs_upper;
 1785                 break;
 1786 
 1787         case CMAPI_SAAL:
 1788                 sl.sl_sap[sli++] = SAP_SSCF_UNI;
 1789                 sl.sl_sap[sli++] = SAP_SSCOP;
 1790                 upf = atm_cm_saal_upper;
 1791                 break;
 1792 
 1793         case CMAPI_SSCOP:
 1794                 sl.sl_sap[sli++] = SAP_SSCOP;
 1795                 upf = atm_cm_sscop_upper;
 1796                 break;
 1797 
 1798         default:
 1799                 upf = NULL;
 1800         }
 1801 
 1802         /*
 1803          * AAL Attributes
 1804          */
 1805         switch (cvp->cvc_attr.aal.type) {
 1806 
 1807         case ATM_AAL5:
 1808                 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
 1809                 sl.sl_sap[sli++] = SAP_SAR_AAL5;
 1810                 sl.sl_sap[sli++] = SAP_ATM;
 1811                 break;
 1812 
 1813         case ATM_AAL3_4:
 1814                 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
 1815                 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
 1816                 sl.sl_sap[sli++] = SAP_ATM;
 1817                 break;
 1818         }
 1819 
 1820         /*
 1821          * Terminate stack list 
 1822          */
 1823         sl.sl_sap[sli] = 0;
 1824 
 1825         /*
 1826          * Create a service stack
 1827          */
 1828         err = atm_create_stack(cvp, &sl, upf);
 1829         if (err) {
 1830                 goto done;
 1831         }
 1832 
 1833         /*
 1834          * Let the signalling manager finish the VCC activation
 1835          */
 1836         switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
 1837 
 1838         case CALL_PROCEEDING:
 1839                 /*
 1840                  * Note that we're not finished yet
 1841                  */
 1842                 err = EINPROGRESS;
 1843                 /* FALLTHRU */
 1844 
 1845         case CALL_CONNECTED:
 1846                 /*
 1847                  * Initialize the stack now, even if the call isn't totally
 1848                  * active yet.  We want to avoid the delay between getting
 1849                  * the "call connected" event and actually notifying the 
 1850                  * adapter to accept cells on the new VCC - if the delay is 
 1851                  * too long, then we end up dropping the first pdus sent by 
 1852                  * the caller.
 1853                  */
 1854                 cvp->cvc_state = CVCS_INIT;
 1855                 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
 1856                                 cvp->cvc_lower, cvp->cvc_tokl, cvp,
 1857                                 cvp->cvc_attr.api_init, 0, err2);
 1858                 if (err2)
 1859                         panic("atm_cm_accept: init");
 1860 
 1861                 if (cvp->cvc_flags & CVCF_ABORTING) {
 1862                         /*
 1863                          * Someone on the stack bailed out...schedule the 
 1864                          * VCC and stack termination
 1865                          */
 1866                         err = ECONNABORTED;
 1867                 } else {
 1868                         /*
 1869                          * Everything looks fine from here
 1870                          */
 1871                         if (err)
 1872                                 cvp->cvc_state = CVCS_ACCEPT;
 1873                         else
 1874                                 cvp->cvc_state = CVCS_ACTIVE;
 1875                 }
 1876                 break;
 1877 
 1878         case CALL_FAILED:
 1879                 /*
 1880                  * Terminate stack and clean up before we leave
 1881                  */
 1882                 cvp->cvc_state = CVCS_CLEAR;
 1883                 break;
 1884 
 1885         default:
 1886                 panic("atm_cm_accept: accept");
 1887         }
 1888 
 1889 done:
 1890         if (err == 0) {
 1891                 /*
 1892                  * Call has been connected, notify endpoints
 1893                  */
 1894                 while (cop) {
 1895                         Atm_connection  *cop2 = cop->co_next;
 1896 
 1897                         cop->co_state = COS_ACTIVE;
 1898                         (*cop->co_endpt->ep_connected)(cop->co_toku);
 1899                         cop = cop2;
 1900                 }
 1901 
 1902         } else if (err == EINPROGRESS) {
 1903                 /*
 1904                  * Call is still in progress, endpoint must wait
 1905                  */
 1906                 err = 0;
 1907 
 1908         } else {
 1909                 /*
 1910                  * Let caller know we failed
 1911                  */
 1912                 cvp->cvc_attr.cause = atm_cause_tmpl;
 1913                 cvp->cvc_attr.cause.v.cause_value =
 1914                                 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
 1915         }
 1916 
 1917         return (err);
 1918 }
 1919 
 1920 
 1921 /*
 1922  * Match Attributes on Listening Queue
 1923  * 
 1924  * This function will attempt to match the supplied connection attributes
 1925  * with one of the registered attributes in the listening queue.  The pcop
 1926  * argument may be supplied in order to allow multiple listeners to share 
 1927  * an incoming call (if supported by the listeners).
 1928  *
 1929  * Called at splnet.
 1930  *
 1931  * Arguments:
 1932  *      ap      pointer to attributes to be matched
 1933  *      pcop    pointer to the previously matched connection
 1934  *
 1935  * Returns:
 1936  *      addr    connection with which a match was found
 1937  *      0       no match found
 1938  *
 1939  */
 1940 Atm_connection *
 1941 atm_cm_match(ap, pcop)
 1942         Atm_attributes  *ap;
 1943         Atm_connection  *pcop;
 1944 {
 1945         Atm_connection  *cop;
 1946         Atm_attributes  *lap;
 1947 
 1948 
 1949         /*
 1950          * If we've already matched a listener...
 1951          */
 1952         if (pcop) {
 1953                 /*
 1954                  * Make sure already matched listener supports sharing
 1955                  */
 1956                 if ((pcop->co_mpx != ATM_ENC_LLC) ||
 1957                     ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
 1958                         return (NULL);
 1959 
 1960                 /*
 1961                  * Position ourselves after the matched entry
 1962                  */
 1963                 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
 1964                         if (cop == pcop) {
 1965                                 cop = pcop->co_next;
 1966                                 break;
 1967                         }
 1968                 }
 1969         } else {
 1970                 /*
 1971                  * Start search at top of listening queue
 1972                  */
 1973                 cop = atm_listen_queue;
 1974         }
 1975 
 1976         /*
 1977          * Search through listening queue
 1978          */
 1979         for (; cop; cop = cop->co_next) {
 1980 
 1981                 lap = cop->co_lattr;
 1982 
 1983                 /*
 1984                  * If we're trying to share, check that this entry allows it
 1985                  */
 1986                 if (pcop) {
 1987                         if ((cop->co_mpx != ATM_ENC_LLC) ||
 1988                             ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
 1989                                 continue;
 1990                 }
 1991 
 1992                 /*
 1993                  * ALL "matchable" attributes must match
 1994                  */
 1995 
 1996                 /*
 1997                  * BHLI
 1998                  */
 1999                 if (lap->bhli.tag == T_ATM_ABSENT) {
 2000                         if (ap->bhli.tag == T_ATM_PRESENT)
 2001                                 continue;
 2002                 } else if (lap->bhli.tag == T_ATM_PRESENT) {
 2003                         if (ap->bhli.tag == T_ATM_ABSENT)
 2004                                 continue;
 2005                         if (ap->bhli.tag == T_ATM_PRESENT)
 2006                                 if (bcmp(&lap->bhli.v, &ap->bhli.v, 
 2007                                                 sizeof(struct t_atm_bhli)))
 2008                                         continue;
 2009                 }
 2010 
 2011                 /*
 2012                  * BLLI Layer 2
 2013                  */
 2014                 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
 2015                         if (ap->blli.tag_l2 == T_ATM_PRESENT)
 2016                                 continue;
 2017                 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
 2018                         if (ap->blli.tag_l2 == T_ATM_ABSENT)
 2019                                 continue;
 2020                         if (ap->blli.tag_l2 == T_ATM_PRESENT) {
 2021                                 if (bcmp(&lap->blli.v.layer_2_protocol.ID,
 2022                                            &ap->blli.v.layer_2_protocol.ID, 
 2023                                            sizeof(
 2024                                               ap->blli.v.layer_2_protocol.ID)))
 2025                                         continue;
 2026                         }
 2027                 }
 2028 
 2029                 /*
 2030                  * BLLI Layer 3
 2031                  */
 2032                 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
 2033                         if (ap->blli.tag_l3 == T_ATM_PRESENT)
 2034                                 continue;
 2035                 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
 2036                         if (ap->blli.tag_l3 == T_ATM_ABSENT)
 2037                                 continue;
 2038                         if (ap->blli.tag_l3 == T_ATM_PRESENT) {
 2039                                 if (bcmp(&lap->blli.v.layer_3_protocol.ID,
 2040                                            &ap->blli.v.layer_3_protocol.ID, 
 2041                                            sizeof(
 2042                                               ap->blli.v.layer_3_protocol.ID)))
 2043                                         continue;
 2044                         }
 2045                 }
 2046 
 2047                 /*
 2048                  * LLC
 2049                  */
 2050                 if (lap->llc.tag == T_ATM_ABSENT) {
 2051                         if (ap->llc.tag == T_ATM_PRESENT)
 2052                                 continue;
 2053                 } else if (lap->llc.tag == T_ATM_PRESENT) {
 2054                         if (ap->llc.tag == T_ATM_ABSENT)
 2055                                 continue;
 2056                         if (ap->llc.tag == T_ATM_PRESENT) {
 2057                                 int     i = MIN(lap->llc.v.llc_len,
 2058                                                         ap->llc.v.llc_len);
 2059 
 2060                                 if (bcmp(lap->llc.v.llc_info,
 2061                                                         ap->llc.v.llc_info, i))
 2062                                         continue;
 2063                         }
 2064                 }
 2065 
 2066                 /*
 2067                  * AAL
 2068                  */
 2069                 if (lap->aal.tag == T_ATM_ABSENT) {
 2070                         if (ap->aal.tag == T_ATM_PRESENT)
 2071                                 continue;
 2072                 } else if (lap->aal.tag == T_ATM_PRESENT) {
 2073                         if (ap->aal.tag == T_ATM_ABSENT)
 2074                                 continue;
 2075                         if (ap->aal.tag == T_ATM_PRESENT) {
 2076                                 if (lap->aal.type != ap->aal.type)
 2077                                         continue;
 2078                                 if (lap->aal.type == ATM_AAL5) {
 2079                                         if (lap->aal.v.aal5.SSCS_type !=
 2080                                                     ap->aal.v.aal5.SSCS_type)
 2081                                                 continue;
 2082                                 } else {
 2083                                         if (lap->aal.v.aal4.SSCS_type !=
 2084                                                     ap->aal.v.aal4.SSCS_type)
 2085                                                 continue;
 2086                                 }
 2087                         }
 2088                 }
 2089 
 2090                 /*
 2091                  * Called Party
 2092                  */
 2093                 if (lap->called.tag == T_ATM_ABSENT) {
 2094                         if (ap->called.tag == T_ATM_PRESENT)
 2095                                 continue;
 2096                 } else if (lap->called.tag == T_ATM_PRESENT) {
 2097                         if (ap->called.tag == T_ATM_ABSENT)
 2098                                 continue;
 2099                         if (ap->called.tag == T_ATM_PRESENT) {
 2100                                 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
 2101                                                 &ap->called.addr)) ||
 2102                                     (!ATM_ADDR_EQUAL(&lap->called.subaddr,
 2103                                                 &ap->called.subaddr)))
 2104                                         continue;
 2105                         }
 2106                 }
 2107 
 2108                 /*
 2109                  * Found a full match - return it
 2110                  */
 2111                 break;
 2112         }
 2113 
 2114         return (cop);
 2115 }
 2116 
 2117 
 2118 /*
 2119  * Find Shareable LLC VCC
 2120  * 
 2121  * Given an endpoint-supplied connection attribute using LLC multiplexing,
 2122  * this function will attempt to locate an existing connection which meets
 2123  * the requirements of the supplied attributes.
 2124  *
 2125  * Called at splnet.
 2126  *
 2127  * Arguments:
 2128  *      ap      pointer to requested attributes
 2129  *
 2130  * Returns:
 2131  *      addr    shareable LLC connection VCC
 2132  *      0       no shareable VCC available
 2133  *
 2134  */
 2135 static Atm_connvc *
 2136 atm_cm_share_llc(ap)
 2137         Atm_attributes  *ap;
 2138 {
 2139         Atm_connection  *cop;
 2140         Atm_connvc      *cvp;
 2141 
 2142         /*
 2143          * Is requestor willing to share?
 2144          */
 2145         if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
 2146                 return (NULL);
 2147 
 2148         /*
 2149          * Try to find a shareable connection
 2150          */
 2151         for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
 2152                         cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
 2153 
 2154                 /*
 2155                  * Dont use terminating connections
 2156                  */
 2157                 switch (cvp->cvc_state) {
 2158 
 2159                 case CVCS_SETUP:
 2160                 case CVCS_ACCEPT:
 2161                 case CVCS_ACTIVE:
 2162                         break;
 2163 
 2164                 default:
 2165                         continue;
 2166                 }
 2167 
 2168                 /*
 2169                  * Is connection LLC and shareable?
 2170                  */
 2171                 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
 2172                     ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
 2173                         continue;
 2174 
 2175                 /*
 2176                  * Match requested attributes with existing connection
 2177                  */
 2178                 if (ap->nif != cvp->cvc_attr.nif)
 2179                         continue;
 2180 
 2181                 if ((ap->api != cvp->cvc_attr.api) ||
 2182                     (ap->api_init != cvp->cvc_attr.api_init))
 2183                         continue;
 2184 
 2185                 /*
 2186                  * Remote Party
 2187                  */
 2188                 if (cvp->cvc_flags & CVCF_CALLER) {
 2189                         if ((!ATM_ADDR_EQUAL(&ap->called.addr,
 2190                                         &cvp->cvc_attr.called.addr)) ||
 2191                             (!ATM_ADDR_EQUAL(&ap->called.subaddr,
 2192                                         &cvp->cvc_attr.called.subaddr)))
 2193                                 continue;
 2194                 } else {
 2195                         if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
 2196                                 continue;
 2197                         if ((!ATM_ADDR_EQUAL(&ap->called.addr,
 2198                                         &cvp->cvc_attr.calling.addr)) ||
 2199                             (!ATM_ADDR_EQUAL(&ap->called.subaddr,
 2200                                         &cvp->cvc_attr.calling.subaddr)))
 2201                                 continue;
 2202                 }
 2203 
 2204                 /*
 2205                  * AAL
 2206                  */
 2207                 if (ap->aal.type == ATM_AAL5) {
 2208                         struct t_atm_aal5       *ap5, *cv5;
 2209 
 2210                         ap5 = &ap->aal.v.aal5;
 2211                         cv5 = &cvp->cvc_attr.aal.v.aal5;
 2212 
 2213                         if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
 2214                             (ap5->SSCS_type != cv5->SSCS_type))
 2215                                 continue;
 2216 
 2217                         if (cvp->cvc_flags & CVCF_CALLER) {
 2218                                 if (ap5->forward_max_SDU_size >
 2219                                                 cv5->forward_max_SDU_size)
 2220                                         continue;
 2221                         } else {
 2222                                 if (ap5->forward_max_SDU_size >
 2223                                                 cv5->backward_max_SDU_size)
 2224                                         continue;
 2225                         }
 2226                 } else {
 2227                         struct t_atm_aal4       *ap4, *cv4;
 2228 
 2229                         ap4 = &ap->aal.v.aal4;
 2230                         cv4 = &cvp->cvc_attr.aal.v.aal4;
 2231 
 2232                         if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
 2233                             (ap4->SSCS_type != cv4->SSCS_type))
 2234                                 continue;
 2235 
 2236                         if (cvp->cvc_flags & CVCF_CALLER) {
 2237                                 if (ap4->forward_max_SDU_size >
 2238                                                 cv4->forward_max_SDU_size)
 2239                                         continue;
 2240                         } else {
 2241                                 if (ap4->forward_max_SDU_size >
 2242                                                 cv4->backward_max_SDU_size)
 2243                                         continue;
 2244                         }
 2245                 }
 2246 
 2247                 /*
 2248                  * Traffic Descriptor
 2249                  */
 2250                 if ((ap->traffic.tag != T_ATM_PRESENT) ||
 2251                     (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
 2252                     (ap->traffic.v.best_effort != T_YES) ||
 2253                     (cvp->cvc_attr.traffic.v.best_effort != T_YES))
 2254                         continue;
 2255 
 2256                 /*
 2257                  * Broadband Bearer
 2258                  */
 2259                 if (ap->bearer.v.connection_configuration !=
 2260                                 cvp->cvc_attr.bearer.v.connection_configuration)
 2261                         continue;
 2262 
 2263                 /*
 2264                  * QOS
 2265                  */
 2266                 if (cvp->cvc_flags & CVCF_CALLER) {
 2267                         if ((ap->qos.v.forward.qos_class !=
 2268                                 cvp->cvc_attr.qos.v.forward.qos_class) ||
 2269                             (ap->qos.v.backward.qos_class !=
 2270                                 cvp->cvc_attr.qos.v.backward.qos_class))
 2271                                 continue;
 2272                 } else {
 2273                         if ((ap->qos.v.forward.qos_class !=
 2274                                 cvp->cvc_attr.qos.v.backward.qos_class) ||
 2275                             (ap->qos.v.backward.qos_class !=
 2276                                 cvp->cvc_attr.qos.v.forward.qos_class))
 2277                                 continue;
 2278                 }
 2279 
 2280                 /*
 2281                  * The new LLC header must also be unique for this VCC
 2282                  */
 2283                 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
 2284                         int     i = MIN(ap->llc.v.llc_len,
 2285                                         cop->co_llc.v.llc_len);
 2286 
 2287                         if (bcmp(ap->llc.v.llc_info, 
 2288                                    cop->co_llc.v.llc_info, i) == 0)
 2289                                 break;
 2290                 }
 2291 
 2292                 /*
 2293                  * If no header overlaps, then we're done
 2294                  */
 2295                 if (cop == NULL)
 2296                         break;
 2297         }
 2298 
 2299         return (cvp);
 2300 }
 2301 
 2302 
 2303 /*
 2304  * Close Connection
 2305  * 
 2306  * This function will terminate a connection, including notifying the
 2307  * user, if necessary, and freeing up control block memory.  The caller
 2308  * is responsible for managing the connection VCC.
 2309  *
 2310  * Called at splnet.
 2311  *
 2312  * Arguments:
 2313  *      cop     pointer to connection block
 2314  *      cause   pointer to cause of close
 2315  *
 2316  * Returns:
 2317  *      none
 2318  *
 2319  */
 2320 static void
 2321 atm_cm_closeconn(cop, cause)
 2322         Atm_connection  *cop;
 2323         struct t_atm_cause      *cause;
 2324 {
 2325 
 2326         /*
 2327          * Decide whether user needs notification
 2328          */
 2329         switch (cop->co_state) {
 2330 
 2331         case COS_OUTCONN:
 2332         case COS_LISTEN:
 2333         case COS_INCONN:
 2334         case COS_INACCEPT:
 2335         case COS_ACTIVE:
 2336                 /*
 2337                  * Yup, let 'em know connection is gone
 2338                  */
 2339                 if (cop->co_toku)
 2340                         (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
 2341                 break;
 2342 
 2343         case COS_CLEAR:
 2344                 /*
 2345                  * Nope,they should know already
 2346                  */
 2347                 break;
 2348 
 2349         default:
 2350                 panic("atm_cm_closeconn: bogus state");
 2351         }
 2352 
 2353         /*
 2354          * Unlink connection from its queues
 2355          */
 2356         switch (cop->co_state) {
 2357 
 2358         case COS_LISTEN:
 2359                 uma_zfree(atm_attributes_zone, cop->co_lattr);
 2360                 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
 2361                 break;
 2362 
 2363         default:
 2364                 /*
 2365                  * Remove connection from multiplexor queue
 2366                  */
 2367                 if (cop->co_mxh != cop) {
 2368                         /*
 2369                          * Connection is down the chain, just unlink it
 2370                          */
 2371                         UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
 2372 
 2373                 } else if (cop->co_next != NULL) {
 2374                         /*
 2375                          * Connection is at the head of a non-singleton chain,
 2376                          * so unlink and reset the chain head
 2377                          */
 2378                         Atm_connection  *t, *nhd;
 2379 
 2380                         t = nhd = cop->co_next;
 2381                         while (t) {
 2382                                 t->co_mxh = nhd;
 2383                                 t = t->co_next;
 2384                         }
 2385                         if (nhd->co_connvc)
 2386                                 nhd->co_connvc->cvc_conn = nhd;
 2387                 }
 2388         }
 2389 
 2390         /*
 2391          * Free the connection block
 2392          */
 2393         cop->co_state = COS_FREE;
 2394         uma_zfree(atm_connection_zone, cop);
 2395         return;
 2396 }
 2397 
 2398 
 2399 /*
 2400  * Close Connection VCC
 2401  * 
 2402  * This function will terminate a connection VCC, including releasing the
 2403  * the call to the signalling manager, terminating the VCC protocol stack,
 2404  * and freeing up control block memory.
 2405  *
 2406  * Called at splnet.
 2407  *
 2408  * Arguments:
 2409  *      cvp     pointer to connection VCC block
 2410  *
 2411  * Returns:
 2412  *      none
 2413  *
 2414  */
 2415 static void
 2416 atm_cm_closevc(cvp)
 2417         Atm_connvc      *cvp;
 2418 {
 2419         int     err;
 2420 
 2421         /*
 2422          * Break links with the connection block
 2423          */
 2424         cvp->cvc_conn = NULL;
 2425 
 2426         /*
 2427          * Cancel any running timer
 2428          */
 2429         CVC_CANCEL(cvp);
 2430 
 2431         /*
 2432          * Free queued packets
 2433          */
 2434         while (cvp->cvc_rcvq) {
 2435                 KBuffer         *m;
 2436 
 2437                 m = cvp->cvc_rcvq;
 2438                 cvp->cvc_rcvq = KB_QNEXT(m);
 2439                 KB_QNEXT(m) = NULL;
 2440                 KB_FREEALL(m);
 2441         }
 2442 
 2443         /*
 2444          * Unlink from any queues
 2445          */
 2446         if (cvp->cvc_flags & CVCF_INCOMQ) {
 2447                 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
 2448                 atm_incoming_qlen--;
 2449                 cvp->cvc_flags &=  ~CVCF_INCOMQ;
 2450 
 2451         } else if (cvp->cvc_flags & CVCF_CONNQ) {
 2452                 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
 2453                 cvp->cvc_flags &=  ~CVCF_CONNQ;
 2454         }
 2455 
 2456         /*
 2457          * Release the signalling call
 2458          */
 2459         switch (cvp->cvc_state) {
 2460 
 2461         case CVCS_SETUP:
 2462         case CVCS_INIT:
 2463         case CVCS_ACCEPT:
 2464         case CVCS_ACTIVE:
 2465         case CVCS_RELEASE:
 2466                 if (cvp->cvc_vcc) {
 2467                         cvp->cvc_state = CVCS_RELEASE;
 2468                         switch ((*cvp->cvc_sigmgr->sm_release)
 2469                                 (cvp->cvc_vcc, &err)) {
 2470 
 2471                         case CALL_CLEARED:
 2472                                 /*
 2473                                  * Looks good so far...
 2474                                  */
 2475                                 break;
 2476 
 2477                         case CALL_PROCEEDING:
 2478                                 /*
 2479                                  * We'll have to wait for the call to clear
 2480                                  */
 2481                                 return;
 2482 
 2483                         case CALL_FAILED:
 2484                                 /*
 2485                                  * If there's a memory shortage, retry later.
 2486                                  * Otherwise who knows what's going on....
 2487                                  */
 2488                                 if ((err == ENOMEM) || (err == ENOBUFS)) {
 2489                                         CVC_TIMER(cvp, 1 * ATM_HZ);
 2490                                         return;
 2491                                 }
 2492                                 log(LOG_ERR,
 2493                                         "atm_cm_closevc: release %d\n", err);
 2494                                 break;
 2495                         }
 2496                 }
 2497                 break;
 2498 
 2499         case CVCS_INCOMING:
 2500         case CVCS_REJECT:
 2501                 if (cvp->cvc_vcc) {
 2502                         cvp->cvc_state = CVCS_REJECT;
 2503                         switch ((*cvp->cvc_sigmgr->sm_reject)
 2504                                 (cvp->cvc_vcc, &err)) {
 2505 
 2506                         case CALL_CLEARED:
 2507                                 /*
 2508                                  * Looks good so far...
 2509                                  */
 2510                                 break;
 2511 
 2512                         case CALL_FAILED:
 2513                                 /*
 2514                                  * If there's a memory shortage, retry later.
 2515                                  * Otherwise who knows what's going on....
 2516                                  */
 2517                                 if ((err == ENOMEM) || (err == ENOBUFS)) {
 2518                                         CVC_TIMER(cvp, 1 * ATM_HZ);
 2519                                         return;
 2520                                 }
 2521                                 log(LOG_ERR,
 2522                                         "atm_cm_closevc: reject %d\n", err);
 2523                                 break;
 2524                         }
 2525                 }
 2526                 break;
 2527 
 2528         case CVCS_CLEAR:
 2529         case CVCS_TERM:
 2530                 /*
 2531                  * No need for anything here
 2532                  */
 2533                 break;
 2534 
 2535         default:
 2536                 panic("atm_cm_closevc: bogus state");
 2537         }
 2538 
 2539         /*
 2540          * Now terminate the stack
 2541          */
 2542         if (cvp->cvc_tokl) {
 2543                 cvp->cvc_state = CVCS_TERM;
 2544 
 2545                 /*
 2546                  * Wait until stack is unwound before terminating
 2547                  */
 2548                 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
 2549                         CVC_TIMER(cvp, 0);
 2550                         return;
 2551                 }
 2552 
 2553                 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
 2554                         cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
 2555 
 2556                 cvp->cvc_tokl = NULL;
 2557         }
 2558 
 2559         /*
 2560          * Let signalling manager finish up
 2561          */
 2562         cvp->cvc_state = CVCS_FREE;
 2563         if (cvp->cvc_vcc) {
 2564                 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
 2565         }
 2566 
 2567         /*
 2568          * Finally, free our own control blocks
 2569          */
 2570         uma_zfree(atm_connvc_zone, cvp);
 2571         return;
 2572 }
 2573 
 2574 
 2575 /*
 2576  * Process a Connection VCC timeout
 2577  * 
 2578  * Called when a previously scheduled cvc control block timer expires.  
 2579  * Processing will be based on the current cvc state.
 2580  *
 2581  * Called at splnet.
 2582  *
 2583  * Arguments:
 2584  *      tip     pointer to cvc timer control block
 2585  *
 2586  * Returns:
 2587  *      none
 2588  *
 2589  */
 2590 static void
 2591 atm_cm_timeout(tip)
 2592         struct atm_time *tip;
 2593 {
 2594         Atm_connection  *cop, *cop2;
 2595         Atm_connvc      *cvp;
 2596 
 2597         /*
 2598          * Back-off to cvc control block
 2599          */
 2600         cvp = (Atm_connvc *)
 2601                         ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
 2602 
 2603         /*
 2604          * Process timeout based on protocol state
 2605          */
 2606         switch (cvp->cvc_state) {
 2607 
 2608         case CVCS_SETUP:
 2609         case CVCS_ACCEPT:
 2610         case CVCS_ACTIVE:
 2611                 /*
 2612                  * Handle VCC abort
 2613                  */
 2614                 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
 2615                         goto logerr;
 2616 
 2617                 /*
 2618                  * Terminate all connections
 2619                  */
 2620                 cop = cvp->cvc_conn;
 2621                 while (cop) {
 2622                         cop2 = cop->co_next;
 2623                         atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
 2624                         cop = cop2;
 2625                 }
 2626 
 2627                 /*
 2628                  * Terminate VCC
 2629                  */
 2630                 atm_cm_closevc(cvp);
 2631 
 2632                 break;
 2633 
 2634         case CVCS_REJECT:
 2635         case CVCS_RELEASE:
 2636         case CVCS_TERM:
 2637                 /*
 2638                  * Retry failed operation
 2639                  */
 2640                 atm_cm_closevc(cvp);
 2641                 break;
 2642 
 2643         default:
 2644 logerr:
 2645                 log(LOG_ERR,
 2646                         "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
 2647                         cvp, cvp->cvc_state);
 2648         }
 2649 }
 2650 
 2651 
 2652 /*
 2653  * CPCS User Control Commands
 2654  * 
 2655  * This function is called by an endpoint user to pass a control command
 2656  * across a CPCS data API.  Mostly we just send these down the stack.
 2657  *
 2658  * Arguments:
 2659  *      cmd     stack command code
 2660  *      cop     pointer to connection block
 2661  *      arg     argument
 2662  *
 2663  * Returns:
 2664  *      0       command output successful
 2665  *      errno   output failed - reason indicated
 2666  *
 2667  */
 2668 int
 2669 atm_cm_cpcs_ctl(cmd, cop, arg)
 2670         int             cmd;
 2671         Atm_connection  *cop;
 2672         void            *arg;
 2673 {
 2674         Atm_connvc      *cvp;
 2675         int             err = 0;
 2676 
 2677         /*
 2678          * Validate connection state
 2679          */
 2680         if (cop->co_state != COS_ACTIVE) {
 2681                 err = EFAULT;
 2682                 goto done;
 2683         }
 2684 
 2685         cvp = cop->co_connvc;
 2686         if (cvp->cvc_state != CVCS_ACTIVE) {
 2687                 err = EFAULT;
 2688                 goto done;
 2689         }
 2690 
 2691         if (cvp->cvc_attr.api != CMAPI_CPCS) {
 2692                 err = EFAULT;
 2693                 goto done;
 2694         }
 2695 
 2696         switch (cmd) {
 2697 
 2698         default:
 2699                 err = EINVAL;
 2700         }
 2701 
 2702 done:
 2703         return (err);
 2704 }
 2705 
 2706 
 2707 /*
 2708  * CPCS Data Output
 2709  * 
 2710  * This function is called by an endpoint user to output a data packet
 2711  * across a CPCS data API.   After we've validated the connection state, the
 2712  * packet will be encapsulated (if necessary) and sent down the data stack.
 2713  *
 2714  * Arguments:
 2715  *      cop     pointer to connection block
 2716  *      m       pointer to packet buffer chain to be output
 2717  *
 2718  * Returns:
 2719  *      0       packet output successful
 2720  *      errno   output failed - reason indicated
 2721  *
 2722  */
 2723 int
 2724 atm_cm_cpcs_data(cop, m)
 2725         Atm_connection  *cop;
 2726         KBuffer         *m;
 2727 {
 2728         Atm_connvc      *cvp;
 2729         struct attr_llc *llcp;
 2730         int             err, space;
 2731         void            *bp;
 2732 
 2733 
 2734         /*
 2735          * Validate connection state
 2736          */
 2737         if (cop->co_state != COS_ACTIVE) {
 2738                 err = EFAULT;
 2739                 goto done;
 2740         }
 2741 
 2742         cvp = cop->co_connvc;
 2743         if (cvp->cvc_state != CVCS_ACTIVE) {
 2744                 err = EFAULT;
 2745                 goto done;
 2746         }
 2747 
 2748         if (cvp->cvc_attr.api != CMAPI_CPCS) {
 2749                 err = EFAULT;
 2750                 goto done;
 2751         }
 2752 
 2753         /*
 2754          * Add any packet encapsulation
 2755          */
 2756         switch (cop->co_mpx) {
 2757 
 2758         case ATM_ENC_NULL:
 2759                 /*
 2760                  * None needed...
 2761                  */
 2762                 break;
 2763 
 2764         case ATM_ENC_LLC:
 2765                 /*
 2766                  * Need to add an LLC header
 2767                  */
 2768                 llcp = &cop->co_llc;
 2769 
 2770                 /*
 2771                  * See if there's room to add LLC header to front of packet.
 2772                  */
 2773                 KB_HEADROOM(m, space);
 2774                 if (space < llcp->v.llc_len) {
 2775                         KBuffer         *n;
 2776 
 2777                         /*
 2778                          * We have to allocate another buffer and tack it
 2779                          * onto the front of the packet
 2780                          */
 2781                         KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT,
 2782                                         KB_T_HEADER);
 2783                         if (n == 0) {
 2784                                 err = ENOMEM;
 2785                                 goto done;
 2786                         }
 2787                         KB_TAILALIGN(n, llcp->v.llc_len);
 2788                         KB_LINKHEAD(n, m);
 2789                         m = n;
 2790                 } else {
 2791                         /*
 2792                          * Header fits, just adjust buffer controls
 2793                          */
 2794                         KB_HEADADJ(m, llcp->v.llc_len);
 2795                 }
 2796 
 2797                 /*
 2798                  * Add the LLC header
 2799                  */
 2800                 KB_DATASTART(m, bp, void *);
 2801                 bcopy(llcp->v.llc_info, bp, llcp->v.llc_len);
 2802                 KB_PLENADJ(m, llcp->v.llc_len);
 2803                 break;
 2804 
 2805         default:
 2806                 panic("atm_cm_cpcs_data: mpx");
 2807         }
 2808 
 2809         /*
 2810          * Finally, we can send the packet on its way
 2811          */
 2812         STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl, 
 2813                 cvp, (intptr_t)m, 0, err);
 2814 
 2815 done:
 2816         return (err);
 2817 }
 2818 
 2819 
 2820 /*
 2821  * Process CPCS Stack Commands
 2822  * 
 2823  * This is the top of the CPCS API data stack.  All upward stack commands 
 2824  * for the CPCS data API will be received and processed here.
 2825  *
 2826  * Arguments:
 2827  *      cmd     stack command code
 2828  *      tok     session token (pointer to connection VCC control block)
 2829  *      arg1    argument 1
 2830  *      arg2    argument 2
 2831  *
 2832  * Returns:
 2833  *      none
 2834  *
 2835  */
 2836 static void
 2837 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
 2838         int             cmd;
 2839         void            *tok;
 2840         intptr_t        arg1;
 2841         intptr_t        arg2;
 2842 {
 2843         Atm_connection  *cop;
 2844         Atm_connvc      *cvp = tok;
 2845         KBuffer         *m;
 2846         void            *bp;
 2847         int             s;
 2848 
 2849         switch (cmd) {
 2850 
 2851         case CPCS_UNITDATA_SIG:
 2852                 /*
 2853                  * Input data packet
 2854                  */
 2855                 m = (KBuffer *)arg1;
 2856 
 2857                 if (cvp->cvc_state != CVCS_ACTIVE) {
 2858                         if (cvp->cvc_state == CVCS_ACCEPT) {
 2859                                 KBuffer *n;
 2860 
 2861                                 /*
 2862                                  * Queue up any packets received before sigmgr
 2863                                  * notifies us of incoming call completion
 2864                                  */
 2865                                 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
 2866                                         KB_FREEALL(m);
 2867                                         atm_cm_stat.cms_rcvconnvc++;
 2868                                         return;
 2869                                 }
 2870                                 KB_QNEXT(m) = NULL;
 2871                                 if (cvp->cvc_rcvq == NULL) {
 2872                                         cvp->cvc_rcvq = m;
 2873                                 } else {
 2874                                         for (n = cvp->cvc_rcvq; 
 2875                                              KB_QNEXT(n) != NULL; 
 2876                                              n = KB_QNEXT(n))
 2877                                                 ;
 2878                                         KB_QNEXT(n) = m;
 2879                                 }
 2880                                 cvp->cvc_rcvqlen++;
 2881                                 return;
 2882                         } else {
 2883                                 KB_FREEALL(m);
 2884                                 atm_cm_stat.cms_rcvconnvc++;
 2885                                 return;
 2886                         }
 2887                 }
 2888 
 2889                 /*
 2890                  * Locate packet's connection
 2891                  */
 2892                 cop = cvp->cvc_conn;
 2893                 switch (cop->co_mpx) {
 2894 
 2895                 case ATM_ENC_NULL:
 2896                         /*
 2897                          * We're already there...
 2898                          */
 2899                         break;
 2900 
 2901                 case ATM_ENC_LLC:
 2902                         /*
 2903                          * Find connection with matching LLC header
 2904                          */
 2905                         if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
 2906                                 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
 2907                                 if (m == 0) {
 2908                                         atm_cm_stat.cms_llcdrop++;
 2909                                         return;
 2910                                 }
 2911                         }
 2912                         KB_DATASTART(m, bp, void *);
 2913 
 2914                         s = splnet();
 2915 
 2916                         while (cop) {
 2917                                 if (bcmp(bp, cop->co_llc.v.llc_info,
 2918                                                 cop->co_llc.v.llc_len) == 0)
 2919                                         break;
 2920                                 cop = cop->co_next;
 2921                         }
 2922 
 2923                         (void) splx(s);
 2924 
 2925                         if (cop == NULL) {
 2926                                 /*
 2927                                  * No connected user for this LLC
 2928                                  */
 2929                                 KB_FREEALL(m);
 2930                                 atm_cm_stat.cms_llcid++;
 2931                                 return;
 2932                         }
 2933 
 2934                         /*
 2935                          * Strip off the LLC header
 2936                          */
 2937                         KB_HEADADJ(m, -cop->co_llc.v.llc_len);
 2938                         KB_PLENADJ(m, -cop->co_llc.v.llc_len);
 2939                         break;
 2940 
 2941                 default:
 2942                         panic("atm_cm_cpcs_upper: mpx");
 2943                 }
 2944 
 2945                 /*
 2946                  * We've found our connection, so hand the packet off
 2947                  */
 2948                 if (cop->co_state != COS_ACTIVE) {
 2949                         KB_FREEALL(m);
 2950                         atm_cm_stat.cms_rcvconn++;
 2951                         return;
 2952                 }
 2953                 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
 2954                 break;
 2955 
 2956         case CPCS_UABORT_SIG:
 2957         case CPCS_PABORT_SIG:
 2958                 /*
 2959                  * We don't support these (yet), so just FALLTHROUGH
 2960                  */
 2961 
 2962         default:
 2963                 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
 2964         }
 2965 }
 2966 
 2967 
 2968 /*
 2969  * SAAL User Control Commands
 2970  * 
 2971  * This function is called by an endpoint user to pass a control command
 2972  * across a SAAL data API.  Mostly we just send these down the stack.
 2973  *
 2974  * Arguments:
 2975  *      cmd     stack command code
 2976  *      cop     pointer to connection block
 2977  *      arg     argument
 2978  *
 2979  * Returns:
 2980  *      0       command output successful
 2981  *      errno   output failed - reason indicated
 2982  *
 2983  */
 2984 int
 2985 atm_cm_saal_ctl(cmd, cop, arg)
 2986         int             cmd;
 2987         Atm_connection  *cop;
 2988         void            *arg;
 2989 {
 2990         Atm_connvc      *cvp;
 2991         int             err = 0;
 2992 
 2993         /*
 2994          * Validate connection state
 2995          */
 2996         if (cop->co_state != COS_ACTIVE) {
 2997                 err = EFAULT;
 2998                 goto done;
 2999         }
 3000 
 3001         cvp = cop->co_connvc;
 3002         if (cvp->cvc_state != CVCS_ACTIVE) {
 3003                 err = EFAULT;
 3004                 goto done;
 3005         }
 3006 
 3007         if (cvp->cvc_attr.api != CMAPI_SAAL) {
 3008                 err = EFAULT;
 3009                 goto done;
 3010         }
 3011 
 3012         switch (cmd) {
 3013 
 3014         case SSCF_UNI_ESTABLISH_REQ:
 3015         case SSCF_UNI_RELEASE_REQ:
 3016                 /*
 3017                  * Pass command down the stack
 3018                  */
 3019                 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp, 
 3020                         (intptr_t)arg, 0, err);
 3021                 break;
 3022 
 3023         default:
 3024                 err = EINVAL;
 3025         }
 3026 
 3027 done:
 3028         return (err);
 3029 }
 3030 
 3031 
 3032 /*
 3033  * SAAL Data Output
 3034  * 
 3035  * This function is called by an endpoint user to output a data packet
 3036  * across a SAAL data API.   After we've validated the connection state,
 3037  * the packet will be sent down the data stack.
 3038  *
 3039  * Arguments:
 3040  *      cop     pointer to connection block
 3041  *      m       pointer to packet buffer chain to be output
 3042  *
 3043  * Returns:
 3044  *      0       packet output successful
 3045  *      errno   output failed - reason indicated
 3046  *
 3047  */
 3048 int
 3049 atm_cm_saal_data(cop, m)
 3050         Atm_connection  *cop;
 3051         KBuffer         *m;
 3052 {
 3053         Atm_connvc      *cvp;
 3054         int             err;
 3055 
 3056 
 3057         /*
 3058          * Validate connection state
 3059          */
 3060         if (cop->co_state != COS_ACTIVE) {
 3061                 err = EFAULT;
 3062                 goto done;
 3063         }
 3064 
 3065         cvp = cop->co_connvc;
 3066         if (cvp->cvc_state != CVCS_ACTIVE) {
 3067                 err = EFAULT;
 3068                 goto done;
 3069         }
 3070 
 3071         if (cvp->cvc_attr.api != CMAPI_SAAL) {
 3072                 err = EFAULT;
 3073                 goto done;
 3074         }
 3075 
 3076         /*
 3077          * Finally, we can send the packet on its way
 3078          */
 3079         STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl, 
 3080                 cvp, (intptr_t)m, 0, err);
 3081 
 3082 done:
 3083         return (err);
 3084 }
 3085 
 3086 
 3087 /*
 3088  * Process SAAL Stack Commands
 3089  * 
 3090  * This is the top of the SAAL API data stack.  All upward stack commands 
 3091  * for the SAAL data API will be received and processed here.
 3092  *
 3093  * Arguments:
 3094  *      cmd     stack command code
 3095  *      tok     session token (pointer to connection VCC control block)
 3096  *      arg1    argument 1
 3097  *      arg2    argument 2
 3098  *
 3099  * Returns:
 3100  *      none
 3101  *
 3102  */
 3103 static void
 3104 atm_cm_saal_upper(cmd, tok, arg1, arg2)
 3105         int             cmd;
 3106         void            *tok;
 3107         intptr_t        arg1;
 3108         intptr_t        arg2;
 3109 {
 3110         Atm_connection  *cop;
 3111         Atm_connvc      *cvp = tok;
 3112 
 3113 
 3114         switch (cmd) {
 3115 
 3116         case SSCF_UNI_ESTABLISH_IND:
 3117         case SSCF_UNI_ESTABLISH_CNF:
 3118         case SSCF_UNI_RELEASE_IND:
 3119         case SSCF_UNI_RELEASE_CNF:
 3120                 /*
 3121                  * Control commands
 3122                  */
 3123                 cop = cvp->cvc_conn;
 3124                 if (cvp->cvc_state != CVCS_ACTIVE)
 3125                         break;
 3126                 if (cop->co_state != COS_ACTIVE)
 3127                         break;
 3128 
 3129                 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
 3130                 break;
 3131 
 3132         case SSCF_UNI_DATA_IND:
 3133                 /*
 3134                  * User data
 3135                  */
 3136                 cop = cvp->cvc_conn;
 3137                 if (cvp->cvc_state != CVCS_ACTIVE) {
 3138                         atm_cm_stat.cms_rcvconnvc++;
 3139                         KB_FREEALL((KBuffer *)arg1);
 3140                         break;
 3141                 }
 3142                 if (cop->co_state != COS_ACTIVE) {
 3143                         atm_cm_stat.cms_rcvconn++;
 3144                         KB_FREEALL((KBuffer *)arg1);
 3145                         break;
 3146                 }
 3147 
 3148                 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
 3149                 break;
 3150 
 3151         case SSCF_UNI_UNITDATA_IND:
 3152                 /*
 3153                  * Not supported
 3154                  */
 3155                 KB_FREEALL((KBuffer *)arg1);
 3156 
 3157                 /* FALLTHRU */
 3158 
 3159         default:
 3160                 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
 3161         }
 3162 }
 3163 
 3164 
 3165 /*
 3166  * SSCOP User Control Commands
 3167  * 
 3168  * This function is called by an endpoint user to pass a control command
 3169  * across a SSCOP data API.  Mostly we just send these down the stack.
 3170  *
 3171  * Arguments:
 3172  *      cmd     stack command code
 3173  *      cop     pointer to connection block
 3174  *      arg1    argument
 3175  *      arg2    argument
 3176  *
 3177  * Returns:
 3178  *      0       command output successful
 3179  *      errno   output failed - reason indicated
 3180  *
 3181  */
 3182 int
 3183 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
 3184         int             cmd;
 3185         Atm_connection  *cop;
 3186         void            *arg1;
 3187         void            *arg2;
 3188 {
 3189         Atm_connvc      *cvp;
 3190         int             err = 0;
 3191 
 3192         /*
 3193          * Validate connection state
 3194          */
 3195         if (cop->co_state != COS_ACTIVE) {
 3196                 err = EFAULT;
 3197                 goto done;
 3198         }
 3199 
 3200         cvp = cop->co_connvc;
 3201         if (cvp->cvc_state != CVCS_ACTIVE) {
 3202                 err = EFAULT;
 3203                 goto done;
 3204         }
 3205 
 3206         if (cvp->cvc_attr.api != CMAPI_SSCOP) {
 3207                 err = EFAULT;
 3208                 goto done;
 3209         }
 3210 
 3211         switch (cmd) {
 3212 
 3213         case SSCOP_ESTABLISH_REQ:
 3214         case SSCOP_ESTABLISH_RSP:
 3215         case SSCOP_RELEASE_REQ:
 3216         case SSCOP_RESYNC_REQ:
 3217         case SSCOP_RESYNC_RSP:
 3218         case SSCOP_RECOVER_RSP:
 3219         case SSCOP_RETRIEVE_REQ:
 3220                 /*
 3221                  * Pass command down the stack
 3222                  */
 3223                 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp, 
 3224                         (intptr_t)arg1, (intptr_t)arg2, err);
 3225                 break;
 3226 
 3227         default:
 3228                 err = EINVAL;
 3229         }
 3230 
 3231 done:
 3232         return (err);
 3233 }
 3234 
 3235 
 3236 /*
 3237  * SSCOP Data Output
 3238  * 
 3239  * This function is called by an endpoint user to output a data packet
 3240  * across a SSCOP data API.   After we've validated the connection state,
 3241  * the packet will be encapsulated and sent down the data stack.
 3242  *
 3243  * Arguments:
 3244  *      cop     pointer to connection block
 3245  *      m       pointer to packet buffer chain to be output
 3246  *
 3247  * Returns:
 3248  *      0       packet output successful
 3249  *      errno   output failed - reason indicated
 3250  *
 3251  */
 3252 int
 3253 atm_cm_sscop_data(cop, m)
 3254         Atm_connection  *cop;
 3255         KBuffer         *m;
 3256 {
 3257         Atm_connvc      *cvp;
 3258         int             err;
 3259 
 3260 
 3261         /*
 3262          * Validate connection state
 3263          */
 3264         if (cop->co_state != COS_ACTIVE) {
 3265                 err = EFAULT;
 3266                 goto done;
 3267         }
 3268 
 3269         cvp = cop->co_connvc;
 3270         if (cvp->cvc_state != CVCS_ACTIVE) {
 3271                 err = EFAULT;
 3272                 goto done;
 3273         }
 3274 
 3275         if (cvp->cvc_attr.api != CMAPI_SSCOP) {
 3276                 err = EFAULT;
 3277                 goto done;
 3278         }
 3279 
 3280         /*
 3281          * Finally, we can send the packet on its way
 3282          */
 3283         STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl, 
 3284                 cvp, (intptr_t)m, 0, err);
 3285 
 3286 done:
 3287         return (err);
 3288 }
 3289 
 3290 
 3291 /*
 3292  * Process SSCOP Stack Commands
 3293  * 
 3294  * This is the top of the SSCOP API data stack.  All upward stack commands 
 3295  * for the SSCOP data API will be received and processed here.
 3296  *
 3297  * Arguments:
 3298  *      cmd     stack command code
 3299  *      tok     session token (pointer to connection VCC control block)
 3300  *      arg1    argument 1
 3301  *      arg2    argument 2
 3302  *
 3303  * Returns:
 3304  *      none
 3305  *
 3306  */
 3307 static void
 3308 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
 3309         int             cmd;
 3310         void            *tok;
 3311         intptr_t        arg1;
 3312         intptr_t        arg2;
 3313 {
 3314         Atm_connection  *cop;
 3315         Atm_connvc      *cvp = tok;
 3316 
 3317         switch (cmd) {
 3318 
 3319         case SSCOP_ESTABLISH_IND:
 3320         case SSCOP_ESTABLISH_CNF:
 3321         case SSCOP_RELEASE_IND:
 3322         case SSCOP_RESYNC_IND:
 3323                 /*
 3324                  * Control commands
 3325                  */
 3326                 cop = cvp->cvc_conn;
 3327                 if ((cvp->cvc_state != CVCS_ACTIVE) ||
 3328                     (cop->co_state != COS_ACTIVE)) {
 3329                         KB_FREEALL((KBuffer *)arg1);
 3330                         break;
 3331                 }
 3332 
 3333                 (*cop->co_endpt->ep_sscop_ctl)
 3334                         (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
 3335                 break;
 3336 
 3337         case SSCOP_RELEASE_CNF:
 3338         case SSCOP_RESYNC_CNF:
 3339         case SSCOP_RECOVER_IND:
 3340         case SSCOP_RETRIEVE_IND:
 3341         case SSCOP_RETRIEVECMP_IND:
 3342                 /*
 3343                  * Control commands
 3344                  */
 3345                 cop = cvp->cvc_conn;
 3346                 if ((cvp->cvc_state != CVCS_ACTIVE) ||
 3347                     (cop->co_state != COS_ACTIVE))
 3348                         break;
 3349 
 3350                 (*cop->co_endpt->ep_sscop_ctl)
 3351                         (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
 3352                 break;
 3353 
 3354         case SSCOP_DATA_IND:
 3355                 /*
 3356                  * User data
 3357                  */
 3358                 cop = cvp->cvc_conn;
 3359                 if (cvp->cvc_state != CVCS_ACTIVE) {
 3360                         atm_cm_stat.cms_rcvconnvc++;
 3361                         KB_FREEALL((KBuffer *)arg1);
 3362                         break;
 3363                 }
 3364                 if (cop->co_state != COS_ACTIVE) {
 3365                         atm_cm_stat.cms_rcvconn++;
 3366                         KB_FREEALL((KBuffer *)arg1);
 3367                         break;
 3368                 }
 3369 
 3370                 (*cop->co_endpt->ep_sscop_data)
 3371                                 (cop->co_toku, (KBuffer *)arg1, arg2);
 3372                 break;
 3373 
 3374         case SSCOP_UNITDATA_IND:
 3375                 /*
 3376                  * Not supported
 3377                  */
 3378                 KB_FREEALL((KBuffer *)arg1);
 3379 
 3380                 /* FALLTHRU */
 3381 
 3382         default:
 3383                 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
 3384         }
 3385 }
 3386 
 3387 
 3388 /*
 3389  * Register an ATM Endpoint Service
 3390  * 
 3391  * Every ATM endpoint service must register itself here before it can 
 3392  * issue or receive any connection requests.
 3393  *
 3394  * Arguments:
 3395  *      epp     pointer to endpoint definition structure
 3396  *
 3397  * Returns:
 3398  *      0       registration successful
 3399  *      errno   registration failed - reason indicated
 3400  *
 3401  */
 3402 int
 3403 atm_endpoint_register(epp)
 3404         Atm_endpoint    *epp;
 3405 {
 3406         int             s = splnet();
 3407 
 3408         /*
 3409          * See if we need to be initialized
 3410          */
 3411         if (!atm_init)
 3412                 atm_initialize();
 3413 
 3414         /*
 3415          * Validate endpoint
 3416          */
 3417         if (epp->ep_id > ENDPT_MAX) {
 3418                 (void) splx(s);
 3419                 return (EINVAL);
 3420         }
 3421         if (atm_endpoints[epp->ep_id] != NULL) {
 3422                 (void) splx(s);
 3423                 return (EEXIST);
 3424         }
 3425 
 3426         /*
 3427          * Add endpoint to list
 3428          */
 3429         atm_endpoints[epp->ep_id] = epp;
 3430 
 3431         (void) splx(s);
 3432         return (0);
 3433 }
 3434 
 3435 
 3436 /*
 3437  * De-register an ATM Endpoint Service
 3438  * 
 3439  * Each ATM endpoint service provider must de-register its registered 
 3440  * endpoint(s) before terminating.  Specifically, loaded kernel modules
 3441  * must de-register their services before unloading themselves.
 3442  *
 3443  * Arguments:
 3444  *      epp     pointer to endpoint definition structure
 3445  *
 3446  * Returns:
 3447  *      0       de-registration successful 
 3448  *      errno   de-registration failed - reason indicated
 3449  *
 3450  */
 3451 int
 3452 atm_endpoint_deregister(epp)
 3453         Atm_endpoint    *epp;
 3454 {
 3455         int     s = splnet();
 3456 
 3457         /*
 3458          * Validate endpoint
 3459          */
 3460         if (epp->ep_id > ENDPT_MAX) {
 3461                 (void) splx(s);
 3462                 return (EINVAL);
 3463         }
 3464         if (atm_endpoints[epp->ep_id] != epp) {
 3465                 (void) splx(s);
 3466                 return (ENOENT);
 3467         }
 3468 
 3469         /*
 3470          * Remove endpoint from list
 3471          */
 3472         atm_endpoints[epp->ep_id] = NULL;
 3473 
 3474         (void) splx(s);
 3475         return (0);
 3476 }
 3477 

Cache object: c720e361a264b90644781d17dbf9c5b2


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