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