config root man

Current Path : /sys/contrib/ngatm/netnatm/api/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //sys/contrib/ngatm/netnatm/api/cc_port.c

/*
 * Copyright (c) 2003-2004
 *	Hartmut Brandt
 *	All rights reserved.
 *
 * Copyright (c) 2001-2002
 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
 *	All rights reserved.
 *
 * Author: Harti Brandt <harti@freebsd.org>
 *
 * Redistribution of this software and documentation and use in source and
 * binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *
 * 1. Redistributions of source code or documentation must retain the above
 *    copyright notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Begemot: libunimsg/netnatm/api/cc_port.c,v 1.1 2004/07/08 08:21:53 brandt Exp $
 *
 * ATM API as defined per af-saa-0108
 *
 * Port-global stuff (ILMI and Co.)
 */
#include <netnatm/unimsg.h>
#include <netnatm/msg/unistruct.h>
#include <netnatm/api/unisap.h>
#include <netnatm/sig/unidef.h>
#include <netnatm/api/atmapi.h>
#include <netnatm/api/ccatm.h>
#include <netnatm/api/ccpriv.h>

/*
 * Find a port with a given number
 */
static struct ccport *
find_port(struct ccdata *cc, u_int portno)
{
	struct ccport *port;

	TAILQ_FOREACH(port, &cc->port_list, node_link)
		if (port->param.port == portno)
			return (port);
	return (NULL);
}

/*
 * Create a new port structure, initialize it and link it to the node.
 * Returns 0 on success, an errno otherwise.
 */
struct ccport *
cc_port_create(struct ccdata *cc, void *uarg, u_int portno)
{
	struct ccport *port, *p1;

	if (portno == 0 || portno > 0xffffffff)
		return (NULL);

	TAILQ_FOREACH(port, &cc->port_list, node_link)
		if (port->param.port == portno)
			return (NULL);

	port = CCZALLOC(sizeof(*port));
	if (port == NULL)
		return (NULL);

	port->uarg = uarg;
	port->cc = cc;
	port->admin = CCPORT_STOPPED;
	LIST_INIT(&port->conn_list);
	TAILQ_INIT(&port->addr_list);
	port->param.port = portno;
	port->param.pcr = 350053;
	port->param.max_vpi_bits = 0;
	port->param.max_vci_bits = 8;
	port->param.max_svpc_vpi = 0;
	port->param.max_svcc_vpi = 0;
	port->param.min_svcc_vci = 32;
	port->param.num_addrs = 0;
	TAILQ_INIT(&port->cookies);

	TAILQ_FOREACH(p1, &cc->port_list, node_link)
		if (p1->param.port > portno) {
			TAILQ_INSERT_BEFORE(p1, port, node_link);
			break;
		}
	if (p1 == NULL)
		TAILQ_INSERT_TAIL(&cc->port_list, port, node_link);

	return (port);
}

/*
 * Destroy a port. This closes all connections and aborts all the users of
 * these connections.
 * This should be called only after work has returned so that no signals
 * are pending.
 */
void
cc_port_destroy(struct ccport *port, int shutdown)
{
	struct ccaddr *addr;
	struct ccreq *r;

	TAILQ_REMOVE(&port->cc->port_list, port, node_link);

	while ((r = TAILQ_FIRST(&port->cookies)) != NULL) {
		TAILQ_REMOVE(&port->cookies, r, link);
		CCFREE(r);
	}

	/*
	 * Abort all connections.
	 */
	while (!LIST_EMPTY(&port->conn_list))
		cc_conn_abort(LIST_FIRST(&port->conn_list), shutdown);

	/*
	 * Free addresses.
	 */
	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
		TAILQ_REMOVE(&port->addr_list, addr, port_link);
		CCFREE(addr);
	}

	CCFREE(port);
}

/*
 * Management is given up on this node. Remove all addresses from the port.
 */
void
cc_unmanage(struct ccdata *cc)
{
	struct ccport *port;
	struct ccaddr *addr;

	TAILQ_FOREACH(port, &cc->port_list, node_link) {
		while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
			TAILQ_REMOVE(&port->addr_list, addr, port_link);
			CCFREE(addr);
		}
	}
}

/*
 * Compare two addresses
 */
static __inline int
addr_eq(const struct uni_addr *a1, const struct uni_addr *a2)
{
	return (a1->type == a2->type && a1->plan == a2->plan &&
	    a1->len == a2->len && memcmp(a1->addr, a2->addr, a1->len) == 0);
}


/*
 * retrieve addresses
 */
int
cc_get_addrs(struct ccdata *cc, u_int portno,
    struct uni_addr **pa, u_int **ports, u_int *count)
{
	struct ccport *port = NULL;
	struct ccaddr *addr;
	struct uni_addr *buf, *ptr;
	u_int *pports;

	/*
	 * If a port number is specified and the port does not exist,
	 * return an error.
	 */
	if (portno != 0)
		if ((port = find_port(cc, portno)) == NULL)
			return (ENOENT);

	/*
	 * Count the addresses
	 */
	*count = 0;
	if (portno != 0) {
		TAILQ_FOREACH(addr, &port->addr_list, port_link)
			(*count)++;
	} else {
		TAILQ_FOREACH(port, &cc->port_list, node_link)
			TAILQ_FOREACH(addr, &port->addr_list, port_link)
				(*count)++;
	}

	buf = CCMALLOC(*count * sizeof(struct uni_addr));
	if (buf == NULL)
		return (ENOMEM);
	ptr = buf;

	*ports = CCMALLOC(*count * sizeof(u_int));
	if (*ports == NULL) {
		CCFREE(buf);
		return (ENOMEM);
	}
	pports = *ports;

	if (portno != 0) {
		TAILQ_FOREACH(addr, &port->addr_list, port_link) {
			*ptr++ = addr->addr;
			*pports++ = portno;
		}
	} else {
		TAILQ_FOREACH(port, &cc->port_list, node_link)
			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
				*ptr++ = addr->addr;
				*pports++ = port->param.port;
			}
	}

	*pa = buf;
	return (0);
}

/*
 * return port number
 */
u_int
cc_port_no(struct ccport *port)
{
	return (port->param.port);
}

/*
 * Address unregisterd.
 */
int
cc_addr_unregister(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
{
	struct ccport *port;
	struct ccaddr *a;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);

	/* Find the address */
	TAILQ_FOREACH(a, &port->addr_list, port_link)
		if (addr_eq(arg, &a->addr)) {
			TAILQ_REMOVE(&port->addr_list, a, port_link);
			CCFREE(a);
			return (0);
		}

	return (ENOENT);
}

/*
 * Address registerd.
 */
int
cc_addr_register(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
{
	struct ccport *port, *p1;
	struct ccaddr *a;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);

	/* maybe we know it already? */
	TAILQ_FOREACH(p1, &port->cc->port_list, node_link)
		TAILQ_FOREACH(a, &p1->addr_list, port_link)
			if (addr_eq(arg, &a->addr))
				return (EISCONN);

	a = CCZALLOC(sizeof(*a));
	if (a == NULL)
		return (ENOMEM);
	a->addr = *arg;

	TAILQ_INSERT_TAIL(&port->addr_list, a, port_link);

	return (0);
}

/*
 * Set/get port parameters.
 */
int
cc_port_get_param(struct ccdata *cc, u_int portno,
    struct atm_port_info *param)
{
	struct ccport *port;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);

	*param = port->param;
	return (0);
}

/* XXX maybe allow only in stopped. */
int
cc_port_set_param(struct ccdata *cc, const struct atm_port_info *param)
{
	struct ccport *port;
	struct ccaddr *addr;

	if ((port = find_port(cc, param->port)) == NULL)
		return (ENOENT);

	port->param = *param;

	port->param.num_addrs = 0;
	TAILQ_FOREACH(addr, &port->addr_list, port_link)
		port->param.num_addrs++;

	return (0);
}

/*
 * get port list
 */
int
cc_port_getlist(struct ccdata *cc, u_int *cnt, u_int **ports)
{
	struct ccport *p;
	u_int n;

	n = 0;
	TAILQ_FOREACH(p, &cc->port_list, node_link)
		n++;

	*ports = CCMALLOC(n * sizeof(u_int));
	if (*ports == NULL)
		return (ENOMEM);

	n = 0;
	TAILQ_FOREACH(p, &cc->port_list, node_link)
		(*ports)[n++] = p->param.port;
	*cnt = n;

	return (0);
}

/*
 * START and STOP signalling
 */
int
cc_port_start(struct ccdata *cc, u_int portno)
{
	struct ccport *port;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);
	if (port->admin != CCPORT_STOPPED)
		return (EISCONN);

	cc->funcs->send_uni_glob(port, port->uarg,
	    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
	port->admin = CCPORT_RUNNING;

	return (0);
}

int
cc_port_stop(struct ccdata *cc, u_int portno)
{
	struct ccport *port;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);
	if (port->admin != CCPORT_RUNNING)
		return (ENOTCONN);

	port->admin = CCPORT_STOPPED;

	/*
	 * Abort all connections.
	 */
	while (!LIST_EMPTY(&port->conn_list))
		cc_conn_destroy(LIST_FIRST(&port->conn_list));

	return (0);
}

/*
 * is port running?
 */
int
cc_port_isrunning(struct ccdata *cc, u_int portno, int *state)
{
	struct ccport *port;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);
	if (port->admin == CCPORT_RUNNING)
		*state = 1;
	else
		*state = 0;
	return (0);
}

/*
 * Clear address and prefix information from the named port.
 */
int
cc_port_clear(struct ccdata *cc, u_int portno)
{
	struct ccaddr *addr;
	struct ccport *port;

	if ((port = find_port(cc, portno)) == NULL)
		return (ENOENT);

	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
		TAILQ_REMOVE(&port->addr_list, addr, port_link);
		CCFREE(addr);
	}
	return (0);
}

/*
 * retrieve info on local ports
 */
struct atm_port_list *
cc_get_local_port_info(struct ccdata *cc, u_int portno, size_t *lenp)
{
	struct atm_port_list *list;
	struct atm_port_info *pp;
	struct uni_addr *aa;
	struct ccaddr *addr;
	struct ccport *port;
	u_int nports, naddrs;

	/*
	 * Count ports and addresses.
	 */
	nports = 0;
	naddrs = 0;
	TAILQ_FOREACH(port, &cc->port_list, node_link) {
		if (portno == 0 || port->param.port == portno) {
			nports++;
			TAILQ_FOREACH(addr, &port->addr_list, port_link)
				naddrs++;
		}
	}

	/*
	 * Size and allocate message
	 */
	*lenp = sizeof(*list) + nports * sizeof(*pp) + naddrs * sizeof(*aa);

	list = CCZALLOC(*lenp);
	if (list == NULL)
		return (NULL);

	/*
	 * Fill the message.
	 */
	list->num_ports = nports;
	list->num_addrs = naddrs;

	pp = (void *)((u_char *)list + sizeof(*list));
	aa = (void *)((u_char *)list + sizeof(*list) + nports * sizeof(*pp));

	TAILQ_FOREACH(port, &cc->port_list, node_link) {
		if (portno == 0 || port->param.port == portno) {
			*pp = port->param;
			pp->num_addrs = 0;
			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
				*aa++ = addr->addr;
				pp->num_addrs++;
			}
			pp++;
		}
	}

	return (list);
}

static struct ccreq *
find_cookie(struct ccport *port, u_int cookie)
{
	struct ccreq *r;

	TAILQ_FOREACH(r, &port->cookies, link)
		if (r->cookie == cookie)
			return (r);
	return (NULL);
}

/*
 * input a response from the UNI layer to CC
 */
int
cc_uni_response(struct ccport *port, u_int cookie, u_int reason, u_int state)
{
	struct ccconn *conn;
	struct ccreq *req;

	if (cookie == 0)
		return (EINVAL);

	if (port->admin != CCPORT_RUNNING)
		return (ENOTCONN);

	if ((req = find_cookie(port, cookie)) == NULL) {
		cc_port_log(port, "UNI response for unknown cookie %u", cookie);
		return (EINVAL);
	}
	conn = req->conn;

	TAILQ_REMOVE(&port->cookies, req, link);
	CCFREE(req);

	if (reason == UNIAPI_OK)
		return (cc_conn_resp(conn, CONN_SIG_OK,
		    cookie, reason, state));
	else
		return (cc_conn_resp(conn, CONN_SIG_ERROR,
		    cookie, reason, state));
}

static struct ccconn *
find_cref(const struct ccport *port, const struct uni_cref *cref)
{
	struct ccconn *conn;

	LIST_FOREACH(conn, &port->conn_list, port_link)
		if (conn->cref.cref == cref->cref &&
		    conn->cref.flag == cref->flag)
			return (conn);
	return (NULL);
}

/*
 * Signal from UNI on this port
 */
int
cc_uni_signal(struct ccport *port, u_int cookie, u_int sig, struct uni_msg *msg)
{
	int error = 0;
	size_t len, ilen = 0;
	struct uni_cref *cref;
	struct ccconn *conn;

	if (port->admin != CCPORT_RUNNING) {
		error = ENOTCONN;
		goto out;
	}
	len = (msg != NULL) ? uni_msg_len(msg) : 0;

	switch ((enum uni_sig)sig) {

	  case UNIAPI_ERROR:
		/* handled above */
		cc_port_log(port, "bad UNIAPI_ERROR cookie=%u", cookie);
		error = EINVAL;
		break;

	  case UNIAPI_CALL_CREATED:
		ilen = sizeof(struct uniapi_call_created);
		if (len != ilen)
			goto bad_len;

		if (cookie != 0) {
			/* outgoing call */
			struct ccreq *req;

			if ((req = find_cookie(port, cookie)) == NULL) {
				cc_port_log(port, "bad cookie %u in CREATE",
				    cookie);
				error = EINVAL;
				goto out;
			}
			conn = req->conn;

		} else {
			if ((conn = cc_conn_create(port->cc)) == NULL) {
				error = ENOMEM;
				goto out;
			}
			cc_conn_ins_port(conn, port);
		}

		cc_conn_sig_msg_nodef(conn, CONN_SIG_CREATED, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_CALL_DESTROYED:
		ilen = sizeof(struct uniapi_call_destroyed);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_call_destroyed *)->cref;
		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig(conn, CONN_SIG_DESTROYED, NULL);
		goto out;

	  case UNIAPI_LINK_ESTABLISH_confirm:
		goto out;

	  case UNIAPI_LINK_RELEASE_confirm:
		/* Ups. If we administratively up, restart the link */
		if (port->admin == CCPORT_RUNNING)
			port->cc->funcs->send_uni_glob(port, port->uarg,
			    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
		goto out;

	  case UNIAPI_PARTY_CREATED:
		ilen = sizeof(struct uniapi_party_created);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_party_created *)->cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg_nodef(conn,
		     CONN_SIG_PARTY_CREATED, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_PARTY_DESTROYED:
		ilen = sizeof(struct uniapi_party_destroyed);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_party_destroyed *)->cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_DESTROYED, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_DROP_PARTY_ACK_indication:	/* UNI -> API */
		ilen = sizeof(struct uniapi_drop_party_ack_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_drop_party_ack_indication *)->drop.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_ACK_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_RESET_indication:			/* UNI -> API */
	    {
		/*
		 * XXX - do the right thing
		 */
		struct uniapi_reset_indication *ind = uni_msg_rptr(msg,
		    struct uniapi_reset_indication *);
		struct uniapi_reset_response *resp;
		struct uni_msg *u;
		
		/*
		 * Construct message to UNI.
		 */
		if ((u = uni_msg_alloc(sizeof(*resp))) == NULL)
			return (ENOMEM);

		resp = uni_msg_wptr(u, struct uniapi_reset_response *);
		memset(resp, 0, sizeof(*resp));
		u->b_wptr += sizeof(*resp);

		resp->restart = ind->restart;
		resp->connid = ind->connid;

		port->cc->funcs->send_uni_glob(port, port->uarg,
		    UNIAPI_RESET_response, 0, u);

		goto out;
	    }

	  case UNIAPI_RELEASE_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_release_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_release_indication *)
		    ->release.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_REL_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_RELEASE_confirm:			/* UNI -> API */
		ilen = sizeof(struct uniapi_release_confirm);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_release_confirm *)
		    ->release.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_REL_CONF, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_SETUP_confirm:			/* UNI -> API */
		ilen = sizeof(struct uniapi_setup_confirm);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_setup_confirm *)
		    ->connect.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_CONFIRM, msg);
		msg = NULL;
		goto out;


	  case UNIAPI_ALERTING_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_alerting_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_alerting_indication *)
		    ->alerting.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_ALERTING_IND, msg);
		msg = NULL;
		goto out;


	  case UNIAPI_PROCEEDING_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_proceeding_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_proceeding_indication *)
		    ->call_proc.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_PROC_IND, msg);
		msg = NULL;
		goto out;


	  case UNIAPI_SETUP_indication:			/* UNI -> API */
		ilen = sizeof(struct uniapi_setup_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_setup_indication *)
		    ->setup.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_SETUP_COMPLETE_indication:	/* UNI -> API */
		ilen = sizeof(struct uniapi_setup_complete_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_setup_complete_indication *)
		    ->connect_ack.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_COMPL, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_PARTY_ALERTING_indication:	/* UNI -> API */
		ilen = sizeof(struct uniapi_party_alerting_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_party_alerting_indication *)->alert.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ALERTING_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_ADD_PARTY_ACK_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_add_party_ack_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_add_party_ack_indication *)->ack.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_ACK_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_ADD_PARTY_REJ_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_add_party_rej_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg,
		    struct uniapi_add_party_rej_indication *)->rej.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_REJ_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_DROP_PARTY_indication:		/* UNI -> API */
		ilen = sizeof(struct uniapi_drop_party_indication);
		if (len != ilen)
			goto bad_len;

		cref = &uni_msg_rptr(msg, struct uniapi_drop_party_indication *)
		    ->drop.hdr.cref;

		if ((conn = find_cref(port, cref)) == NULL)
			goto unk_call;

		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_IND, msg);
		msg = NULL;
		goto out;

	  case UNIAPI_RESET_confirm:			/* UNI -> API */
	  case UNIAPI_RESET_ERROR_indication:		/* UNI -> API */
	  case UNIAPI_RESET_STATUS_indication:		/* UNI -> API */
		/* XXX */
		goto out;

	  case UNIAPI_NOTIFY_indication:		/* UNI -> API */
	  case UNIAPI_STATUS_indication:		/* UNI -> API */
		break;

	  case UNIAPI_ADD_PARTY_indication:		/* UNI -> API */
		/* not supported by the API */
		break;

	/*
	 * All these are illegal in this direction
	 */
	  case UNIAPI_LINK_ESTABLISH_request:		/* API -> UNI */
	  case UNIAPI_LINK_RELEASE_request:		/* API -> UNI */
	  case UNIAPI_RESET_request:			/* API -> UNI */
	  case UNIAPI_RESET_response:			/* API -> UNI */
	  case UNIAPI_RESET_ERROR_response:		/* API -> UNI */
	  case UNIAPI_SETUP_request:			/* API -> UNI */
	  case UNIAPI_SETUP_response:			/* API -> UNI */
	  case UNIAPI_ALERTING_request:			/* API -> UNI */
	  case UNIAPI_PROCEEDING_request:		/* API -> UNI */
	  case UNIAPI_RELEASE_request:			/* API -> UNI */
	  case UNIAPI_RELEASE_response:			/* API -> UNI */
	  case UNIAPI_NOTIFY_request:			/* API -> UNI */
	  case UNIAPI_STATUS_ENQUIRY_request:		/* API -> UNI */
	  case UNIAPI_ADD_PARTY_request:		/* API -> UNI */
	  case UNIAPI_PARTY_ALERTING_request:		/* API -> UNI */
	  case UNIAPI_ADD_PARTY_ACK_request:		/* API -> UNI */
	  case UNIAPI_ADD_PARTY_REJ_request:		/* API -> UNI */
	  case UNIAPI_DROP_PARTY_request:		/* API -> UNI */
	  case UNIAPI_DROP_PARTY_ACK_request:		/* API -> UNI */
	  case UNIAPI_ABORT_CALL_request:		/* API -> UNI */
	  case UNIAPI_SETUP_COMPLETE_request:		/* API -> UNI */
	  case UNIAPI_MAXSIG:
		break;
	}
	cc_port_log(port, "bad signal %u", sig);
	error = EINVAL;
	goto out;

  bad_len:
	cc_port_log(port, "signal %u bad length: %zu, need %zu", len, ilen);
	error = EINVAL;
	goto out;

  unk_call:
	cc_port_log(port, "unknown call %u/%u", cref->cref, cref->flag);
	error = EINVAL;

  out:
	if (msg != NULL)
		uni_msg_destroy(msg);
	return (error);
}


Man Man