11573Srgrimes/*
21573Srgrimes * Copyright (c) 2003-2004
31573Srgrimes *	Hartmut Brandt
41573Srgrimes *	All rights reserved.
51573Srgrimes *
61573Srgrimes * Copyright (c) 2001-2002
71573Srgrimes *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
81573Srgrimes *	All rights reserved.
91573Srgrimes *
101573Srgrimes * Author: Harti Brandt <harti@freebsd.org>
111573Srgrimes *
121573Srgrimes * Redistribution of this software and documentation and use in source and
131573Srgrimes * binary forms, with or without modification, are permitted provided that
141573Srgrimes * the following conditions are met:
151573Srgrimes *
16148834Sstefanf * 1. Redistributions of source code or documentation must retain the above
171573Srgrimes *    copyright notice, this list of conditions and the following disclaimer.
181573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191573Srgrimes *    notice, this list of conditions and the following disclaimer in the
201573Srgrimes *    documentation and/or other materials provided with the distribution.
211573Srgrimes *
221573Srgrimes * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
231573Srgrimes * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
241573Srgrimes * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
251573Srgrimes * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
261573Srgrimes * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
271573Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
281573Srgrimes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
291573Srgrimes * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
301573Srgrimes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
311573Srgrimes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
321573Srgrimes * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33167457Sstefanf *
3463948Sache * $Begemot: libunimsg/netnatm/api/cc_port.c,v 1.1 2004/07/08 08:21:53 brandt Exp $
351573Srgrimes *
361573Srgrimes * ATM API as defined per af-saa-0108
371573Srgrimes *
381573Srgrimes * Port-global stuff (ILMI and Co.)
391573Srgrimes */
401573Srgrimes#include <netnatm/unimsg.h>
4184260Sobrien#include <netnatm/msg/unistruct.h>
421573Srgrimes#include <netnatm/api/unisap.h>
431573Srgrimes#include <netnatm/sig/unidef.h>
441573Srgrimes#include <netnatm/api/atmapi.h>
4584260Sobrien#include <netnatm/api/ccatm.h>
46148834Sstefanf#include <netnatm/api/ccpriv.h>
4784260Sobrien
4884260Sobrien/*
4984260Sobrien * Find a port with a given number
501573Srgrimes */
511573Srgrimesstatic struct ccport *
521573Srgrimesfind_port(struct ccdata *cc, u_int portno)
53148834Sstefanf{
5484260Sobrien	struct ccport *port;
5584260Sobrien
5684260Sobrien	TAILQ_FOREACH(port, &cc->port_list, node_link)
5784260Sobrien		if (port->param.port == portno)
5884260Sobrien			return (port);
5984260Sobrien	return (NULL);
6084260Sobrien}
6184260Sobrien
6284260Sobrien/*
6384260Sobrien * Create a new port structure, initialize it and link it to the node.
6484260Sobrien * Returns 0 on success, an errno otherwise.
6584260Sobrien */
6684260Sobrienstruct ccport *
6784260Sobriencc_port_create(struct ccdata *cc, void *uarg, u_int portno)
6884260Sobrien{
6984260Sobrien	struct ccport *port, *p1;
7084260Sobrien
711573Srgrimes	if (portno == 0 || portno > 0xffffffff)
721573Srgrimes		return (NULL);
731573Srgrimes
741573Srgrimes	TAILQ_FOREACH(port, &cc->port_list, node_link)
751573Srgrimes		if (port->param.port == portno)
7684260Sobrien			return (NULL);
7784260Sobrien
7884260Sobrien	port = CCZALLOC(sizeof(*port));
7984260Sobrien	if (port == NULL)
8084260Sobrien		return (NULL);
8184260Sobrien
8284260Sobrien	port->uarg = uarg;
831573Srgrimes	port->cc = cc;
8484260Sobrien	port->admin = CCPORT_STOPPED;
8584260Sobrien	LIST_INIT(&port->conn_list);
8684260Sobrien	TAILQ_INIT(&port->addr_list);
87148834Sstefanf	port->param.port = portno;
8884260Sobrien	port->param.pcr = 350053;
8984260Sobrien	port->param.max_vpi_bits = 0;
9084260Sobrien	port->param.max_vci_bits = 8;
9184260Sobrien	port->param.max_svpc_vpi = 0;
9284260Sobrien	port->param.max_svcc_vpi = 0;
9384260Sobrien	port->param.min_svcc_vci = 32;
9484260Sobrien	port->param.num_addrs = 0;
9584260Sobrien	TAILQ_INIT(&port->cookies);
96148834Sstefanf
97148834Sstefanf	TAILQ_FOREACH(p1, &cc->port_list, node_link)
98148834Sstefanf		if (p1->param.port > portno) {
9984260Sobrien			TAILQ_INSERT_BEFORE(p1, port, node_link);
100148834Sstefanf			break;
101148834Sstefanf		}
102148834Sstefanf	if (p1 == NULL)
103148834Sstefanf		TAILQ_INSERT_TAIL(&cc->port_list, port, node_link);
104148834Sstefanf
105167457Sstefanf	return (port);
10684260Sobrien}
10784260Sobrien
1081573Srgrimes/*
1091573Srgrimes * Destroy a port. This closes all connections and aborts all the users of
1101573Srgrimes * these connections.
1111573Srgrimes * This should be called only after work has returned so that no signals
11284260Sobrien * are pending.
1131573Srgrimes */
11484260Sobrienvoid
11584260Sobriencc_port_destroy(struct ccport *port, int shutdown)
11684260Sobrien{
11784260Sobrien	struct ccaddr *addr;
11884260Sobrien	struct ccreq *r;
119148834Sstefanf
12084260Sobrien	TAILQ_REMOVE(&port->cc->port_list, port, node_link);
12184260Sobrien
12284260Sobrien	while ((r = TAILQ_FIRST(&port->cookies)) != NULL) {
1231573Srgrimes		TAILQ_REMOVE(&port->cookies, r, link);
1241573Srgrimes		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 */
147void
148cc_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 */
164static __inline int
165addr_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 */
175int
176cc_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 */
237u_int
238cc_port_no(struct ccport *port)
239{
240	return (port->param.port);
241}
242
243/*
244 * Address unregisterd.
245 */
246int
247cc_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 */
269int
270cc_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 */
297int
298cc_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. */
311int
312cc_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 */
332int
333cc_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 */
357int
358cc_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
374int
375cc_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 */
398int
399cc_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 */
415int
416cc_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 */
434struct atm_port_list *
435cc_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
490static struct ccreq *
491find_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 */
504int
505cc_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
533static struct ccconn *
534find_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 */
548int
549cc_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