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

Cache object: 9e54a7a3c2fc5b484def1712ed897184


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