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