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

Cache object: 467693899b917467ffb9b56d7a44e93e


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