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