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

Cache object: 02a43a539961f1e8c0d493bc9e9028ba


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