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