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