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