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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e1546b32692cb99cc5357d21a4f69e17


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