1 /*
2  * Copyright (c) 2003-2004
3  *	Hartmut Brandt
4  *	All rights reserved.
5  *
6  * Copyright (c) 2001-2002
7  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
8  *	All rights reserved.
9  *
10  * Author: Harti Brandt <[email protected]>
11  *
12  * Redistribution of this software and documentation and use in source and
13  * binary forms, with or without modification, are permitted provided that
14  * the following conditions are met:
15  *
16  * 1. Redistributions of source code or documentation must retain the above
17  *    copyright notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
23  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26  * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Begemot: libunimsg/netnatm/api/cc_port.c,v 1.1 2004/07/08 08:21:53 brandt Exp $
35  *
36  * ATM API as defined per af-saa-0108
37  *
38  * Port-global stuff (ILMI and Co.)
39  */
40 #include <netnatm/unimsg.h>
41 #include <netnatm/msg/unistruct.h>
42 #include <netnatm/api/unisap.h>
43 #include <netnatm/sig/unidef.h>
44 #include <netnatm/api/atmapi.h>
45 #include <netnatm/api/ccatm.h>
46 #include <netnatm/api/ccpriv.h>
47 
48 /*
49  * Find a port with a given number
50  */
51 static struct ccport *
find_port(struct ccdata * cc,u_int portno)52 find_port(struct ccdata *cc, u_int portno)
53 {
54 	struct ccport *port;
55 
56 	TAILQ_FOREACH(port, &cc->port_list, node_link)
57 		if (port->param.port == portno)
58 			return (port);
59 	return (NULL);
60 }
61 
62 /*
63  * Create a new port structure, initialize it and link it to the node.
64  * Returns 0 on success, an errno otherwise.
65  */
66 struct ccport *
cc_port_create(struct ccdata * cc,void * uarg,u_int portno)67 cc_port_create(struct ccdata *cc, void *uarg, u_int portno)
68 {
69 	struct ccport *port, *p1;
70 
71 	if (portno == 0 || portno > 0xffffffff)
72 		return (NULL);
73 
74 	TAILQ_FOREACH(port, &cc->port_list, node_link)
75 		if (port->param.port == portno)
76 			return (NULL);
77 
78 	port = CCZALLOC(sizeof(*port));
79 	if (port == NULL)
80 		return (NULL);
81 
82 	port->uarg = uarg;
83 	port->cc = cc;
84 	port->admin = CCPORT_STOPPED;
85 	LIST_INIT(&port->conn_list);
86 	TAILQ_INIT(&port->addr_list);
87 	port->param.port = portno;
88 	port->param.pcr = 350053;
89 	port->param.max_vpi_bits = 0;
90 	port->param.max_vci_bits = 8;
91 	port->param.max_svpc_vpi = 0;
92 	port->param.max_svcc_vpi = 0;
93 	port->param.min_svcc_vci = 32;
94 	port->param.num_addrs = 0;
95 	TAILQ_INIT(&port->cookies);
96 
97 	TAILQ_FOREACH(p1, &cc->port_list, node_link)
98 		if (p1->param.port > portno) {
99 			TAILQ_INSERT_BEFORE(p1, port, node_link);
100 			break;
101 		}
102 	if (p1 == NULL)
103 		TAILQ_INSERT_TAIL(&cc->port_list, port, node_link);
104 
105 	return (port);
106 }
107 
108 /*
109  * Destroy a port. This closes all connections and aborts all the users of
110  * these connections.
111  * This should be called only after work has returned so that no signals
112  * are pending.
113  */
114 void
cc_port_destroy(struct ccport * port,int shutdown)115 cc_port_destroy(struct ccport *port, int shutdown)
116 {
117 	struct ccaddr *addr;
118 	struct ccreq *r;
119 
120 	TAILQ_REMOVE(&port->cc->port_list, port, node_link);
121 
122 	while ((r = TAILQ_FIRST(&port->cookies)) != NULL) {
123 		TAILQ_REMOVE(&port->cookies, r, link);
124 		CCFREE(r);
125 	}
126 
127 	/*
128 	 * Abort all connections.
129 	 */
130 	while (!LIST_EMPTY(&port->conn_list))
131 		cc_conn_abort(LIST_FIRST(&port->conn_list), shutdown);
132 
133 	/*
134 	 * Free addresses.
135 	 */
136 	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
137 		TAILQ_REMOVE(&port->addr_list, addr, port_link);
138 		CCFREE(addr);
139 	}
140 
141 	CCFREE(port);
142 }
143 
144 /*
145  * Management is given up on this node. Remove all addresses from the port.
146  */
147 void
cc_unmanage(struct ccdata * cc)148 cc_unmanage(struct ccdata *cc)
149 {
150 	struct ccport *port;
151 	struct ccaddr *addr;
152 
153 	TAILQ_FOREACH(port, &cc->port_list, node_link) {
154 		while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
155 			TAILQ_REMOVE(&port->addr_list, addr, port_link);
156 			CCFREE(addr);
157 		}
158 	}
159 }
160 
161 /*
162  * Compare two addresses
163  */
164 static __inline int
addr_eq(const struct uni_addr * a1,const struct uni_addr * a2)165 addr_eq(const struct uni_addr *a1, const struct uni_addr *a2)
166 {
167 	return (a1->type == a2->type && a1->plan == a2->plan &&
168 	    a1->len == a2->len && memcmp(a1->addr, a2->addr, a1->len) == 0);
169 }
170 
171 
172 /*
173  * retrieve addresses
174  */
175 int
cc_get_addrs(struct ccdata * cc,u_int portno,struct uni_addr ** pa,u_int ** ports,u_int * count)176 cc_get_addrs(struct ccdata *cc, u_int portno,
177     struct uni_addr **pa, u_int **ports, u_int *count)
178 {
179 	struct ccport *port = NULL;
180 	struct ccaddr *addr;
181 	struct uni_addr *buf, *ptr;
182 	u_int *pports;
183 
184 	/*
185 	 * If a port number is specified and the port does not exist,
186 	 * return an error.
187 	 */
188 	if (portno != 0)
189 		if ((port = find_port(cc, portno)) == NULL)
190 			return (ENOENT);
191 
192 	/*
193 	 * Count the addresses
194 	 */
195 	*count = 0;
196 	if (portno != 0) {
197 		TAILQ_FOREACH(addr, &port->addr_list, port_link)
198 			(*count)++;
199 	} else {
200 		TAILQ_FOREACH(port, &cc->port_list, node_link)
201 			TAILQ_FOREACH(addr, &port->addr_list, port_link)
202 				(*count)++;
203 	}
204 
205 	buf = CCMALLOC(*count * sizeof(struct uni_addr));
206 	if (buf == NULL)
207 		return (ENOMEM);
208 	ptr = buf;
209 
210 	*ports = CCMALLOC(*count * sizeof(u_int));
211 	if (*ports == NULL) {
212 		CCFREE(buf);
213 		return (ENOMEM);
214 	}
215 	pports = *ports;
216 
217 	if (portno != 0) {
218 		TAILQ_FOREACH(addr, &port->addr_list, port_link) {
219 			*ptr++ = addr->addr;
220 			*pports++ = portno;
221 		}
222 	} else {
223 		TAILQ_FOREACH(port, &cc->port_list, node_link)
224 			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
225 				*ptr++ = addr->addr;
226 				*pports++ = port->param.port;
227 			}
228 	}
229 
230 	*pa = buf;
231 	return (0);
232 }
233 
234 /*
235  * return port number
236  */
237 u_int
cc_port_no(struct ccport * port)238 cc_port_no(struct ccport *port)
239 {
240 	return (port->param.port);
241 }
242 
243 /*
244  * Address unregisterd.
245  */
246 int
cc_addr_unregister(struct ccdata * cc,u_int portno,const struct uni_addr * arg)247 cc_addr_unregister(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
248 {
249 	struct ccport *port;
250 	struct ccaddr *a;
251 
252 	if ((port = find_port(cc, portno)) == NULL)
253 		return (ENOENT);
254 
255 	/* Find the address */
256 	TAILQ_FOREACH(a, &port->addr_list, port_link)
257 		if (addr_eq(arg, &a->addr)) {
258 			TAILQ_REMOVE(&port->addr_list, a, port_link);
259 			CCFREE(a);
260 			return (0);
261 		}
262 
263 	return (ENOENT);
264 }
265 
266 /*
267  * Address registerd.
268  */
269 int
cc_addr_register(struct ccdata * cc,u_int portno,const struct uni_addr * arg)270 cc_addr_register(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
271 {
272 	struct ccport *port, *p1;
273 	struct ccaddr *a;
274 
275 	if ((port = find_port(cc, portno)) == NULL)
276 		return (ENOENT);
277 
278 	/* maybe we know it already? */
279 	TAILQ_FOREACH(p1, &port->cc->port_list, node_link)
280 		TAILQ_FOREACH(a, &p1->addr_list, port_link)
281 			if (addr_eq(arg, &a->addr))
282 				return (EISCONN);
283 
284 	a = CCZALLOC(sizeof(*a));
285 	if (a == NULL)
286 		return (ENOMEM);
287 	a->addr = *arg;
288 
289 	TAILQ_INSERT_TAIL(&port->addr_list, a, port_link);
290 
291 	return (0);
292 }
293 
294 /*
295  * Set/get port parameters.
296  */
297 int
cc_port_get_param(struct ccdata * cc,u_int portno,struct atm_port_info * param)298 cc_port_get_param(struct ccdata *cc, u_int portno,
299     struct atm_port_info *param)
300 {
301 	struct ccport *port;
302 
303 	if ((port = find_port(cc, portno)) == NULL)
304 		return (ENOENT);
305 
306 	*param = port->param;
307 	return (0);
308 }
309 
310 /* XXX maybe allow only in stopped. */
311 int
cc_port_set_param(struct ccdata * cc,const struct atm_port_info * param)312 cc_port_set_param(struct ccdata *cc, const struct atm_port_info *param)
313 {
314 	struct ccport *port;
315 	struct ccaddr *addr;
316 
317 	if ((port = find_port(cc, param->port)) == NULL)
318 		return (ENOENT);
319 
320 	port->param = *param;
321 
322 	port->param.num_addrs = 0;
323 	TAILQ_FOREACH(addr, &port->addr_list, port_link)
324 		port->param.num_addrs++;
325 
326 	return (0);
327 }
328 
329 /*
330  * get port list
331  */
332 int
cc_port_getlist(struct ccdata * cc,u_int * cnt,u_int ** ports)333 cc_port_getlist(struct ccdata *cc, u_int *cnt, u_int **ports)
334 {
335 	struct ccport *p;
336 	u_int n;
337 
338 	n = 0;
339 	TAILQ_FOREACH(p, &cc->port_list, node_link)
340 		n++;
341 
342 	*ports = CCMALLOC(n * sizeof(u_int));
343 	if (*ports == NULL)
344 		return (ENOMEM);
345 
346 	n = 0;
347 	TAILQ_FOREACH(p, &cc->port_list, node_link)
348 		(*ports)[n++] = p->param.port;
349 	*cnt = n;
350 
351 	return (0);
352 }
353 
354 /*
355  * START and STOP signalling
356  */
357 int
cc_port_start(struct ccdata * cc,u_int portno)358 cc_port_start(struct ccdata *cc, u_int portno)
359 {
360 	struct ccport *port;
361 
362 	if ((port = find_port(cc, portno)) == NULL)
363 		return (ENOENT);
364 	if (port->admin != CCPORT_STOPPED)
365 		return (EISCONN);
366 
367 	cc->funcs->send_uni_glob(port, port->uarg,
368 	    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
369 	port->admin = CCPORT_RUNNING;
370 
371 	return (0);
372 }
373 
374 int
cc_port_stop(struct ccdata * cc,u_int portno)375 cc_port_stop(struct ccdata *cc, u_int portno)
376 {
377 	struct ccport *port;
378 
379 	if ((port = find_port(cc, portno)) == NULL)
380 		return (ENOENT);
381 	if (port->admin != CCPORT_RUNNING)
382 		return (ENOTCONN);
383 
384 	port->admin = CCPORT_STOPPED;
385 
386 	/*
387 	 * Abort all connections.
388 	 */
389 	while (!LIST_EMPTY(&port->conn_list))
390 		cc_conn_destroy(LIST_FIRST(&port->conn_list));
391 
392 	return (0);
393 }
394 
395 /*
396  * is port running?
397  */
398 int
cc_port_isrunning(struct ccdata * cc,u_int portno,int * state)399 cc_port_isrunning(struct ccdata *cc, u_int portno, int *state)
400 {
401 	struct ccport *port;
402 
403 	if ((port = find_port(cc, portno)) == NULL)
404 		return (ENOENT);
405 	if (port->admin == CCPORT_RUNNING)
406 		*state = 1;
407 	else
408 		*state = 0;
409 	return (0);
410 }
411 
412 /*
413  * Clear address and prefix information from the named port.
414  */
415 int
cc_port_clear(struct ccdata * cc,u_int portno)416 cc_port_clear(struct ccdata *cc, u_int portno)
417 {
418 	struct ccaddr *addr;
419 	struct ccport *port;
420 
421 	if ((port = find_port(cc, portno)) == NULL)
422 		return (ENOENT);
423 
424 	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
425 		TAILQ_REMOVE(&port->addr_list, addr, port_link);
426 		CCFREE(addr);
427 	}
428 	return (0);
429 }
430 
431 /*
432  * retrieve info on local ports
433  */
434 struct atm_port_list *
cc_get_local_port_info(struct ccdata * cc,u_int portno,size_t * lenp)435 cc_get_local_port_info(struct ccdata *cc, u_int portno, size_t *lenp)
436 {
437 	struct atm_port_list *list;
438 	struct atm_port_info *pp;
439 	struct uni_addr *aa;
440 	struct ccaddr *addr;
441 	struct ccport *port;
442 	u_int nports, naddrs;
443 
444 	/*
445 	 * Count ports and addresses.
446 	 */
447 	nports = 0;
448 	naddrs = 0;
449 	TAILQ_FOREACH(port, &cc->port_list, node_link) {
450 		if (portno == 0 || port->param.port == portno) {
451 			nports++;
452 			TAILQ_FOREACH(addr, &port->addr_list, port_link)
453 				naddrs++;
454 		}
455 	}
456 
457 	/*
458 	 * Size and allocate message
459 	 */
460 	*lenp = sizeof(*list) + nports * sizeof(*pp) + naddrs * sizeof(*aa);
461 
462 	list = CCZALLOC(*lenp);
463 	if (list == NULL)
464 		return (NULL);
465 
466 	/*
467 	 * Fill the message.
468 	 */
469 	list->num_ports = nports;
470 	list->num_addrs = naddrs;
471 
472 	pp = (void *)((u_char *)list + sizeof(*list));
473 	aa = (void *)((u_char *)list + sizeof(*list) + nports * sizeof(*pp));
474 
475 	TAILQ_FOREACH(port, &cc->port_list, node_link) {
476 		if (portno == 0 || port->param.port == portno) {
477 			*pp = port->param;
478 			pp->num_addrs = 0;
479 			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
480 				*aa++ = addr->addr;
481 				pp->num_addrs++;
482 			}
483 			pp++;
484 		}
485 	}
486 
487 	return (list);
488 }
489 
490 static struct ccreq *
find_cookie(struct ccport * port,u_int cookie)491 find_cookie(struct ccport *port, u_int cookie)
492 {
493 	struct ccreq *r;
494 
495 	TAILQ_FOREACH(r, &port->cookies, link)
496 		if (r->cookie == cookie)
497 			return (r);
498 	return (NULL);
499 }
500 
501 /*
502  * input a response from the UNI layer to CC
503  */
504 int
cc_uni_response(struct ccport * port,u_int cookie,u_int reason,u_int state)505 cc_uni_response(struct ccport *port, u_int cookie, u_int reason, u_int state)
506 {
507 	struct ccconn *conn;
508 	struct ccreq *req;
509 
510 	if (cookie == 0)
511 		return (EINVAL);
512 
513 	if (port->admin != CCPORT_RUNNING)
514 		return (ENOTCONN);
515 
516 	if ((req = find_cookie(port, cookie)) == NULL) {
517 		cc_port_log(port, "UNI response for unknown cookie %u", cookie);
518 		return (EINVAL);
519 	}
520 	conn = req->conn;
521 
522 	TAILQ_REMOVE(&port->cookies, req, link);
523 	CCFREE(req);
524 
525 	if (reason == UNIAPI_OK)
526 		return (cc_conn_resp(conn, CONN_SIG_OK,
527 		    cookie, reason, state));
528 	else
529 		return (cc_conn_resp(conn, CONN_SIG_ERROR,
530 		    cookie, reason, state));
531 }
532 
533 static struct ccconn *
find_cref(const struct ccport * port,const struct uni_cref * cref)534 find_cref(const struct ccport *port, const struct uni_cref *cref)
535 {
536 	struct ccconn *conn;
537 
538 	LIST_FOREACH(conn, &port->conn_list, port_link)
539 		if (conn->cref.cref == cref->cref &&
540 		    conn->cref.flag == cref->flag)
541 			return (conn);
542 	return (NULL);
543 }
544 
545 /*
546  * Signal from UNI on this port
547  */
548 int
cc_uni_signal(struct ccport * port,u_int cookie,u_int sig,struct uni_msg * msg)549 cc_uni_signal(struct ccport *port, u_int cookie, u_int sig, struct uni_msg *msg)
550 {
551 	int error = 0;
552 	size_t len, ilen = 0;
553 	struct uni_cref *cref;
554 	struct ccconn *conn;
555 
556 	if (port->admin != CCPORT_RUNNING) {
557 		error = ENOTCONN;
558 		goto out;
559 	}
560 	len = (msg != NULL) ? uni_msg_len(msg) : 0;
561 
562 	switch ((enum uni_sig)sig) {
563 
564 	  case UNIAPI_ERROR:
565 		/* handled above */
566 		cc_port_log(port, "bad UNIAPI_ERROR cookie=%u", cookie);
567 		error = EINVAL;
568 		break;
569 
570 	  case UNIAPI_CALL_CREATED:
571 		ilen = sizeof(struct uniapi_call_created);
572 		if (len != ilen)
573 			goto bad_len;
574 
575 		if (cookie != 0) {
576 			/* outgoing call */
577 			struct ccreq *req;
578 
579 			if ((req = find_cookie(port, cookie)) == NULL) {
580 				cc_port_log(port, "bad cookie %u in CREATE",
581 				    cookie);
582 				error = EINVAL;
583 				goto out;
584 			}
585 			conn = req->conn;
586 
587 		} else {
588 			if ((conn = cc_conn_create(port->cc)) == NULL) {
589 				error = ENOMEM;
590 				goto out;
591 			}
592 			cc_conn_ins_port(conn, port);
593 		}
594 
595 		cc_conn_sig_msg_nodef(conn, CONN_SIG_CREATED, msg);
596 		msg = NULL;
597 		goto out;
598 
599 	  case UNIAPI_CALL_DESTROYED:
600 		ilen = sizeof(struct uniapi_call_destroyed);
601 		if (len != ilen)
602 			goto bad_len;
603 
604 		cref = &uni_msg_rptr(msg, struct uniapi_call_destroyed *)->cref;
605 		if ((conn = find_cref(port, cref)) == NULL)
606 			goto unk_call;
607 
608 		error = cc_conn_sig(conn, CONN_SIG_DESTROYED, NULL);
609 		goto out;
610 
611 	  case UNIAPI_LINK_ESTABLISH_confirm:
612 		goto out;
613 
614 	  case UNIAPI_LINK_RELEASE_confirm:
615 		/* Ups. If we administratively up, restart the link */
616 		if (port->admin == CCPORT_RUNNING)
617 			port->cc->funcs->send_uni_glob(port, port->uarg,
618 			    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
619 		goto out;
620 
621 	  case UNIAPI_PARTY_CREATED:
622 		ilen = sizeof(struct uniapi_party_created);
623 		if (len != ilen)
624 			goto bad_len;
625 
626 		cref = &uni_msg_rptr(msg, struct uniapi_party_created *)->cref;
627 
628 		if ((conn = find_cref(port, cref)) == NULL)
629 			goto unk_call;
630 
631 		error = cc_conn_sig_msg_nodef(conn,
632 		     CONN_SIG_PARTY_CREATED, msg);
633 		msg = NULL;
634 		goto out;
635 
636 	  case UNIAPI_PARTY_DESTROYED:
637 		ilen = sizeof(struct uniapi_party_destroyed);
638 		if (len != ilen)
639 			goto bad_len;
640 
641 		cref = &uni_msg_rptr(msg,
642 		    struct uniapi_party_destroyed *)->cref;
643 
644 		if ((conn = find_cref(port, cref)) == NULL)
645 			goto unk_call;
646 
647 		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_DESTROYED, msg);
648 		msg = NULL;
649 		goto out;
650 
651 	  case UNIAPI_DROP_PARTY_ACK_indication:	/* UNI -> API */
652 		ilen = sizeof(struct uniapi_drop_party_ack_indication);
653 		if (len != ilen)
654 			goto bad_len;
655 
656 		cref = &uni_msg_rptr(msg,
657 		    struct uniapi_drop_party_ack_indication *)->drop.hdr.cref;
658 
659 		if ((conn = find_cref(port, cref)) == NULL)
660 			goto unk_call;
661 
662 		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_ACK_IND, msg);
663 		msg = NULL;
664 		goto out;
665 
666 	  case UNIAPI_RESET_indication:			/* UNI -> API */
667 	    {
668 		/*
669 		 * XXX - do the right thing
670 		 */
671 		struct uniapi_reset_indication *ind = uni_msg_rptr(msg,
672 		    struct uniapi_reset_indication *);
673 		struct uniapi_reset_response *resp;
674 		struct uni_msg *u;
675 
676 		/*
677 		 * Construct message to UNI.
678 		 */
679 		if ((u = uni_msg_alloc(sizeof(*resp))) == NULL)
680 			return (ENOMEM);
681 
682 		resp = uni_msg_wptr(u, struct uniapi_reset_response *);
683 		memset(resp, 0, sizeof(*resp));
684 		u->b_wptr += sizeof(*resp);
685 
686 		resp->restart = ind->restart;
687 		resp->connid = ind->connid;
688 
689 		port->cc->funcs->send_uni_glob(port, port->uarg,
690 		    UNIAPI_RESET_response, 0, u);
691 
692 		goto out;
693 	    }
694 
695 	  case UNIAPI_RELEASE_indication:		/* UNI -> API */
696 		ilen = sizeof(struct uniapi_release_indication);
697 		if (len != ilen)
698 			goto bad_len;
699 
700 		cref = &uni_msg_rptr(msg, struct uniapi_release_indication *)
701 		    ->release.hdr.cref;
702 
703 		if ((conn = find_cref(port, cref)) == NULL)
704 			goto unk_call;
705 
706 		error = cc_conn_sig_msg(conn, CONN_SIG_REL_IND, msg);
707 		msg = NULL;
708 		goto out;
709 
710 	  case UNIAPI_RELEASE_confirm:			/* UNI -> API */
711 		ilen = sizeof(struct uniapi_release_confirm);
712 		if (len != ilen)
713 			goto bad_len;
714 
715 		cref = &uni_msg_rptr(msg, struct uniapi_release_confirm *)
716 		    ->release.hdr.cref;
717 
718 		if ((conn = find_cref(port, cref)) == NULL)
719 			goto unk_call;
720 
721 		error = cc_conn_sig_msg(conn, CONN_SIG_REL_CONF, msg);
722 		msg = NULL;
723 		goto out;
724 
725 	  case UNIAPI_SETUP_confirm:			/* UNI -> API */
726 		ilen = sizeof(struct uniapi_setup_confirm);
727 		if (len != ilen)
728 			goto bad_len;
729 
730 		cref = &uni_msg_rptr(msg, struct uniapi_setup_confirm *)
731 		    ->connect.hdr.cref;
732 
733 		if ((conn = find_cref(port, cref)) == NULL)
734 			goto unk_call;
735 
736 		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_CONFIRM, msg);
737 		msg = NULL;
738 		goto out;
739 
740 
741 	  case UNIAPI_ALERTING_indication:		/* UNI -> API */
742 		ilen = sizeof(struct uniapi_alerting_indication);
743 		if (len != ilen)
744 			goto bad_len;
745 
746 		cref = &uni_msg_rptr(msg, struct uniapi_alerting_indication *)
747 		    ->alerting.hdr.cref;
748 
749 		if ((conn = find_cref(port, cref)) == NULL)
750 			goto unk_call;
751 
752 		error = cc_conn_sig_msg(conn, CONN_SIG_ALERTING_IND, msg);
753 		msg = NULL;
754 		goto out;
755 
756 
757 	  case UNIAPI_PROCEEDING_indication:		/* UNI -> API */
758 		ilen = sizeof(struct uniapi_proceeding_indication);
759 		if (len != ilen)
760 			goto bad_len;
761 
762 		cref = &uni_msg_rptr(msg, struct uniapi_proceeding_indication *)
763 		    ->call_proc.hdr.cref;
764 
765 		if ((conn = find_cref(port, cref)) == NULL)
766 			goto unk_call;
767 
768 		error = cc_conn_sig_msg(conn, CONN_SIG_PROC_IND, msg);
769 		msg = NULL;
770 		goto out;
771 
772 
773 	  case UNIAPI_SETUP_indication:			/* UNI -> API */
774 		ilen = sizeof(struct uniapi_setup_indication);
775 		if (len != ilen)
776 			goto bad_len;
777 
778 		cref = &uni_msg_rptr(msg, struct uniapi_setup_indication *)
779 		    ->setup.hdr.cref;
780 
781 		if ((conn = find_cref(port, cref)) == NULL)
782 			goto unk_call;
783 
784 		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_IND, msg);
785 		msg = NULL;
786 		goto out;
787 
788 	  case UNIAPI_SETUP_COMPLETE_indication:	/* UNI -> API */
789 		ilen = sizeof(struct uniapi_setup_complete_indication);
790 		if (len != ilen)
791 			goto bad_len;
792 
793 		cref = &uni_msg_rptr(msg,
794 		    struct uniapi_setup_complete_indication *)
795 		    ->connect_ack.hdr.cref;
796 
797 		if ((conn = find_cref(port, cref)) == NULL)
798 			goto unk_call;
799 
800 		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_COMPL, msg);
801 		msg = NULL;
802 		goto out;
803 
804 	  case UNIAPI_PARTY_ALERTING_indication:	/* UNI -> API */
805 		ilen = sizeof(struct uniapi_party_alerting_indication);
806 		if (len != ilen)
807 			goto bad_len;
808 
809 		cref = &uni_msg_rptr(msg,
810 		    struct uniapi_party_alerting_indication *)->alert.hdr.cref;
811 
812 		if ((conn = find_cref(port, cref)) == NULL)
813 			goto unk_call;
814 
815 		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ALERTING_IND, msg);
816 		msg = NULL;
817 		goto out;
818 
819 	  case UNIAPI_ADD_PARTY_ACK_indication:		/* UNI -> API */
820 		ilen = sizeof(struct uniapi_add_party_ack_indication);
821 		if (len != ilen)
822 			goto bad_len;
823 
824 		cref = &uni_msg_rptr(msg,
825 		    struct uniapi_add_party_ack_indication *)->ack.hdr.cref;
826 
827 		if ((conn = find_cref(port, cref)) == NULL)
828 			goto unk_call;
829 
830 		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_ACK_IND, msg);
831 		msg = NULL;
832 		goto out;
833 
834 	  case UNIAPI_ADD_PARTY_REJ_indication:		/* UNI -> API */
835 		ilen = sizeof(struct uniapi_add_party_rej_indication);
836 		if (len != ilen)
837 			goto bad_len;
838 
839 		cref = &uni_msg_rptr(msg,
840 		    struct uniapi_add_party_rej_indication *)->rej.hdr.cref;
841 
842 		if ((conn = find_cref(port, cref)) == NULL)
843 			goto unk_call;
844 
845 		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_REJ_IND, msg);
846 		msg = NULL;
847 		goto out;
848 
849 	  case UNIAPI_DROP_PARTY_indication:		/* UNI -> API */
850 		ilen = sizeof(struct uniapi_drop_party_indication);
851 		if (len != ilen)
852 			goto bad_len;
853 
854 		cref = &uni_msg_rptr(msg, struct uniapi_drop_party_indication *)
855 		    ->drop.hdr.cref;
856 
857 		if ((conn = find_cref(port, cref)) == NULL)
858 			goto unk_call;
859 
860 		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_IND, msg);
861 		msg = NULL;
862 		goto out;
863 
864 	  case UNIAPI_RESET_confirm:			/* UNI -> API */
865 	  case UNIAPI_RESET_ERROR_indication:		/* UNI -> API */
866 	  case UNIAPI_RESET_STATUS_indication:		/* UNI -> API */
867 		/* XXX */
868 		goto out;
869 
870 	  case UNIAPI_NOTIFY_indication:		/* UNI -> API */
871 	  case UNIAPI_STATUS_indication:		/* UNI -> API */
872 		break;
873 
874 	  case UNIAPI_ADD_PARTY_indication:		/* UNI -> API */
875 		/* not supported by the API */
876 		break;
877 
878 	/*
879 	 * All these are illegal in this direction
880 	 */
881 	  case UNIAPI_LINK_ESTABLISH_request:		/* API -> UNI */
882 	  case UNIAPI_LINK_RELEASE_request:		/* API -> UNI */
883 	  case UNIAPI_RESET_request:			/* API -> UNI */
884 	  case UNIAPI_RESET_response:			/* API -> UNI */
885 	  case UNIAPI_RESET_ERROR_response:		/* API -> UNI */
886 	  case UNIAPI_SETUP_request:			/* API -> UNI */
887 	  case UNIAPI_SETUP_response:			/* API -> UNI */
888 	  case UNIAPI_ALERTING_request:			/* API -> UNI */
889 	  case UNIAPI_PROCEEDING_request:		/* API -> UNI */
890 	  case UNIAPI_RELEASE_request:			/* API -> UNI */
891 	  case UNIAPI_RELEASE_response:			/* API -> UNI */
892 	  case UNIAPI_NOTIFY_request:			/* API -> UNI */
893 	  case UNIAPI_STATUS_ENQUIRY_request:		/* API -> UNI */
894 	  case UNIAPI_ADD_PARTY_request:		/* API -> UNI */
895 	  case UNIAPI_PARTY_ALERTING_request:		/* API -> UNI */
896 	  case UNIAPI_ADD_PARTY_ACK_request:		/* API -> UNI */
897 	  case UNIAPI_ADD_PARTY_REJ_request:		/* API -> UNI */
898 	  case UNIAPI_DROP_PARTY_request:		/* API -> UNI */
899 	  case UNIAPI_DROP_PARTY_ACK_request:		/* API -> UNI */
900 	  case UNIAPI_ABORT_CALL_request:		/* API -> UNI */
901 	  case UNIAPI_SETUP_COMPLETE_request:		/* API -> UNI */
902 	  case UNIAPI_MAXSIG:
903 		break;
904 	}
905 	cc_port_log(port, "bad signal %u", sig);
906 	error = EINVAL;
907 	goto out;
908 
909   bad_len:
910 	cc_port_log(port, "signal %u bad length: %zu, need %zu", len, ilen);
911 	error = EINVAL;
912 	goto out;
913 
914   unk_call:
915 	cc_port_log(port, "unknown call %u/%u", cref->cref, cref->flag);
916 	error = EINVAL;
917 
918   out:
919 	if (msg != NULL)
920 		uni_msg_destroy(msg);
921 	return (error);
922 }
923 
924