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