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