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