summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ngatm/netnatm/api/cc_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ngatm/netnatm/api/cc_port.c')
-rw-r--r--sys/contrib/ngatm/netnatm/api/cc_port.c923
1 files changed, 923 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/api/cc_port.c b/sys/contrib/ngatm/netnatm/api/cc_port.c
new file mode 100644
index 0000000..f01a723
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/api/cc_port.c
@@ -0,0 +1,923 @@
+/*
+ * 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);
+}
+
OpenPOWER on IntegriCloud