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