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