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