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