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