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